/*jslint white: true, undef: true, nomen: true, regexp: true, bitwise: true, strict: true, browser: true, bitwise: true */
/*jshint globalstrict: true*/
"use strict";
var H = {};
H.type = "12c";
H.touch_display = false;
H.vertical_layout = false;
H.embedded = false;
H.disp_theo_width = 700.0;
H.disp_theo_height = 438.0;
H.disp_key_offset_x = 44.0 - 6;
H.disp_key_offset_y = 151.0 - 18;
H.disp_key_dist_x = (606.0 - 44.0) / 9;
H.disp_key_dist_y = 70;
H.disp_key_width = H.disp_key_dist_x; // 54;
H.disp_key_height = H.disp_key_dist_y; // 50;
H.disp_fb_offset_x = 6;
H.disp_fb_offset_y = 15;
H.disp_fb_width = 50;
H.disp_fb_height = 45;
/*jslint white: true, undef: true, nomen: true, regexp: true, strict: true, browser: true, bitwise: true */
/*jshint globalstrict: true*/
/*global H */
"use strict";
H.getElem = function (id)
{
return document.getElementById(id);
};
H.createElem = function (typ)
{
return document.createElement(typ);
};
H.badnumber = function (res)
{
return (isNaN(res) || ! isFinite(res));
};
H.clamp = function (res)
{
res = res || 0; // just in case it is NaN
res = Math.max(res, -H.value_max);
res = Math.min(res, H.value_max);
return res;
};
H.binary_sgn = function (val)
{
return (val >= 0 ? 1 : -1);
};
H.cl5_round = function (val, decs)
{
var scale = Math.pow(10, decs);
return Math.round(Math.abs(val) * scale) / scale * H.binary_sgn(val);
};
H.trim = function (stringToTrim) {
return stringToTrim.replace(/^\s+|\s+$/g, "");
};
H.zeropad = function (s, n)
{
s = "" + s;
while (s.length < n) {
s = "0" + s;
}
return s;
};
H.spacepad = function (s, n)
{
s = "" + s;
while (s.length < n) {
s = " " + s;
}
return s;
};
H.i18n = function (s, comma, dp0, non_decimal, nosep)
{
var grouping = 3;
if (non_decimal) {
grouping = 4;
if (comma === H.INDIAN_SEPARATOR) {
comma = H.POINT_DECIMAL_SEPARATOR;
}
}
// dp0 means: add decimal point after a whole number
var dpos = s.indexOf('.');
if (dpos === -1 && dp0) {
s += ".";
dpos = s.length - 1;
}
/* Replace decimal point by comma */
if (dpos !== -1 && comma === H.COMMA_DECIMAL_SEPARATOR) {
s = s.slice(0, dpos) + ',' + s.slice(dpos + 1);
}
if (dpos == -1) {
// no decimal separator
// phantom position to satisfy loop ahead
dpos = s.length;
}
if (! nosep) {
/* Thousands separator */
var ts = (comma === H.COMMA_DECIMAL_SEPARATOR) ? "." : ",";
/* find where whole part begins */
var dstop = 0;
while (dstop < s.length && isNaN(parseInt(s.charAt(dstop), 16))) {
++dstop;
}
/* Add thousands separator, from right to left */
for (var e = dpos - grouping; e > dstop; e -= grouping) {
s = s.slice(0, e) + ts + s.slice(e);
if (comma === H.INDIAN_SEPARATOR) {
// India numeric system: 1234567.1 -> 12,34,567.1
grouping = 2;
}
}
}
return s;
};
H.tzoffset = function (d)
{
// returns the time zone offset, expressed as "hours *behind* UTC".
// that would be 180 minutes for Brazil (-0300) and -60 minutes for Germany (+0100)
return d.getTimezoneOffset() * 60000;
};
H.date_check = function (year, month, day)
{
var daymax = 31;
if (month == 4 || month == 6 || month == 9 || month == 11) {
daymax = 30;
} else if (month == 2) {
daymax = 28;
if ((year % 4) === 0 && (((year % 100) !== 0) || ((year % 400) === 0))) {
// leap: divisible by 4 and not ending with 00
// years ending in 00 but divisible by 400 are leap!
daymax = 29;
}
}
if (day <= 0 || day > daymax || year <= 0 || year > 9999 || month <= 0 || month > 12) {
return 0;
}
return 1;
};
H.date_interpret = function (n, dmy)
{
n = Math.round(Math.abs(n) * 1000000);
var day = Math.round(n / 1000000) % 100;
var month = Math.round(n / 10000) % 100;
var year = Math.round(n % 10000);
if (! dmy) {
var tmp = day;
day = month;
month = tmp;
}
if (! H.date_check(year, month, day)) {
return null;
}
// set date at noon, so daylight savings timezone transtion will not change the day.
return new Date(year, month - 1, day, 12, 0, 0);
};
H.date_diff = function (d1, d2)
{
// Dates' timezones may be different because of daylight savings, so we
// need to compensate for.
//
// Math.round could be enough to do this compensation, but we prefer to
// be twice as safe.
return Math.round(((d2.getTime() - H.tzoffset(d2)) - (d1.getTime() - H.tzoffset(d1))) / 86400000);
};
H.date_add = function (dbase, days)
{
// daylight savings timezone not a problem as long as dbase is > 1:01am,
// so even 1 or 2 hour changes will not change the day.
dbase.setTime(dbase.getTime() + Math.floor(days) * 86400000);
};
H.date_diff30 = function (d1, d2)
{
var dd1 = d1.getDate();
var dd2 = d2.getDate();
var z1 = dd1;
var z2 = dd2;
if (dd1 == 31) {
z1 = 30;
}
if (dd2 == 31) {
if (dd1 >= 30) {
z2 = 30;
}
}
var fdt1 = 360 * d1.getFullYear() + 30 * (d1.getMonth() + 1) + z1;
var fdt2 = 360 * d2.getFullYear() + 30 * (d2.getMonth() + 1) + z2;
return fdt2 - fdt1;
};
H.date_gen = function (dd, dmy)
{
if (dmy) {
return dd.getDate() + (dd.getMonth() + 1) / 100 + dd.getFullYear() / 1000000;
} else {
return (dd.getMonth() + 1) + dd.getDate() / 100 + dd.getFullYear() / 1000000;
}
};
H.date_to_show = function (dd, dmy)
{
var dow = dd.getDay();
if (dow === 0) {
dow = 7;
}
var datestring = "";
if (dmy) {
datestring = " " + H.spacepad(dd.getDate(), 2) + "." +
H.zeropad(dd.getMonth() + 1, 2) + "." +
H.zeropad(dd.getFullYear(), 4);
} else {
datestring = " " + H.spacepad(dd.getMonth() + 1, 2) + "." +
H.zeropad(dd.getDate(), 2) + "." +
H.zeropad(dd.getFullYear(), 4);
}
return datestring + " " + dow;
};
H.is_12c = function ()
{
return H.type === "12c" ||
H.type === "12c-platinum" ||
H.type === "12c-bs";
};
/* Some browsers don't have window.console.log */
window.console = window.console || {};
window.console.log = window.console.log || function (msg) {};
// should default to console.log in production
window.xlog = window.xlog || function (msg) { window.console.log(msg); };
// should be null in production
window.console.ut_snap = window.console.ut_snap || function (mode) {};
H.type_cookie = "hp12c";
if (H.type === "12c-platinum") {
H.type_cookie = "hp12cpl";
} else if (H.type === "12c-bs") {
H.type_cookie = "hp12cbs";
} else if (H.type === "11c") {
H.type_cookie = "hp11c";
} else if (H.type === "10c") {
H.type_cookie = "hp10c";
} else if (H.type === "15c") {
H.type_cookie = "hp15c";
} else if (H.type === "16c") {
H.type_cookie = "hp16c";
}
H.INTERACTIVE = 0;
H.PROGRAMMING = 1;
H.RUNNING = 2;
H.RUNNING_STEP = 3;
H.RUNNING_STEP_PRE = 4;
// financial constants (12c)
H.FIN_N = 0;
H.FIN_I = 1;
H.FIN_PV = 2;
H.FIN_PMT = 3;
H.FIN_FV = 4;
// Statistics (map to stomemory)
H.STAT_N = 1;
H.STAT_X = 2;
H.STAT_X2 = 3;
H.STAT_Y = 4;
H.STAT_Y2 = 5;
H.STAT_XY = 6;
if (H.type === "11c" || H.type === "10c") {
H.STAT_N = 0;
H.STAT_X = 1;
H.STAT_X2 = 2;
H.STAT_Y = 3;
H.STAT_Y2 = 4;
H.STAT_XY = 5;
} else if (H.type === "15c") {
H.STAT_N = 2;
H.STAT_X = 3;
H.STAT_X2 = 4;
H.STAT_Y = 5;
H.STAT_Y2 = 6;
H.STAT_XY = 7;
}
H.STAT_MIN = H.STAT_N;
H.STAT_MAX = H.STAT_XY;
// 11C
H.TRIGO_DEG = 0;
H.TRIGO_RAD = 1;
H.TRIGO_GRAD = 2;
// 11C, 15C
H.NOTATION_FIX = 0;
H.NOTATION_SCI = 1;
H.NOTATION_ENG = 2;
// 16C
H.NOTATION_INT = 10; // just for comparisons
H.NOTATION_INT_DEC = H.NOTATION_INT + 1;
H.NOTATION_INT_HEX = H.NOTATION_INT + 2;
H.NOTATION_INT_OCT = H.NOTATION_INT + 3;
H.NOTATION_INT_BIN = H.NOTATION_INT + 4;
H.DEFAULT_WORDSIZE = 16;
H.disp_digits = [];
H.disp_digits[H.NOTATION_INT_HEX] = 8;
H.disp_digits[H.NOTATION_INT_OCT] = 8;
H.disp_digits[H.NOTATION_INT_DEC] = 8; // or 10?
H.disp_digits[H.NOTATION_INT_BIN] = 8;
H.digit_bits = [];
H.digit_bits[H.NOTATION_INT_HEX] = 4;
H.digit_bits[H.NOTATION_INT_OCT] = 3;
H.digit_bits[H.NOTATION_INT_DEC] = Math.log(10) / Math.log(2); // ~3.32 bits
H.digit_bits[H.NOTATION_INT_BIN] = 1;
H.radix = [];
H.radix[H.NOTATION_INT_HEX] = 16;
H.radix[H.NOTATION_INT_OCT] = 8;
H.radix[H.NOTATION_INT_BIN] = 2;
H.radix[H.NOTATION_INT_DEC] = 10;
// just to simplify some functions that query radix
H.radix[H.NOTATION_FIX] = 10;
H.radix[H.NOTATION_SCI] = 10;
H.radix[H.NOTATION_ENG] = 10;
H.radix_suffix = [];
H.radix_suffix[H.NOTATION_INT_HEX] = "h";
H.radix_suffix[H.NOTATION_INT_OCT] = "o";
H.radix_suffix[H.NOTATION_INT_DEC] = "d";
H.radix_suffix[H.NOTATION_INT_BIN] = "b";
H.value_max = 9.999999 * 1e99;
H.value_min = 1e-99;
// 12C defaults
H.ram_MAX = 100;
H.ram_ADDR_SIZE = 2; // e.g. 43.33.00, 43 and 33 are 2 digits
H.STOP_INSTRUCTION = "43.33.00"; // e.g. GTO 00 has 2-digit addr
H.STOP_INSTRUCTION_IS_INVALID = false;
H.INSTRUCTION_SIZE = 2; // size of a non-addr opcode
H.INSTRUCTION_MAX = 100;
H.INSTRUCTION_TOKENS = 3; // e.g. 43.33.00 has 3 tokens
// 12c-BS has the same defaults as 12C vanilla
if (H.type === "12c-platinum") {
H.ram_MAX = 400;
H.ram_ADDR_SIZE = 3;
H.STOP_INSTRUCTION = "43.33.000";
} else if (H.type === "11c") {
H.ram_MAX = 204;
H.ram_ADDR_SIZE = 3;
H.STOP_INSTRUCTION = "50";
H.STOP_INSTRUCTION_IS_INVALID = true;
} else if (H.type === "10c") {
H.STOP_INSTRUCTION = "22.00";
H.ram_MAX = 80;
} else if (H.type === "16c") {
H.ram_MAX = 204;
H.ram_ADDR_SIZE = 3;
H.STOP_INSTRUCTION = "50";
H.STOP_INSTRUCTION_IS_INVALID = true;
} else if (H.type === "15c") {
H.ram_MAX = 448;
H.ram_ADDR_SIZE = 3;
H.STOP_INSTRUCTION = "50";
H.STOP_INSTRUCTION_IS_INVALID = true;
H.INSTRUCTION_TOKENS = 4; // big 15c exception
}
H.MEM_MAX = 20;
// 12C-BS the same defaults as vanilla
if (H.type == "12c-platinum") {
H.MEM_MAX = 30;
} else if (H.type == "16c") {
H.MEM_MAX = 100;
} else if (H.type === "15c") {
H.MEM_MAX = 66;
} else if (H.type === "10c") {
H.MEM_MAX = 10;
}
H.FLAGS_MAX = 2;
if (H.type === "16c") {
H.FLAGS_MAX = 6;
} else if (H.type === "15c") {
H.FLAGS_MAX = 10;
}
// Decimal separators
H.POINT_DECIMAL_SEPARATOR = 0;
H.COMMA_DECIMAL_SEPARATOR = 1;
H.INDIAN_SEPARATOR = 2;
H.SEPARATORS = 3;
// 16C flags
H.FLAG_ZEROS = 3;
H.FLAG_CARRY = 4;
H.FLAG_OVERFLOW = 5;
// 15C flags
H.FLAG_COMPLEX = 8;
if (H.type === "15c") {
H.FLAG_OVERFLOW = 9;
}
// ############### Errors
H.ERROR_DIVZERO = 0;
H.ERROR_OVERFLOW = 1;
H.ERROR_STAT = 2;
H.ERROR_IP = 4;
// 11C, 15C
H.ERROR_INDEX = 3;
H.ERROR_RTN = 5;
H.ERROR_FLAG = 6;
// 15C
H.ERROR_MATRIX_OP = 1;
H.ERROR_RECURSIVE_SOLVE = 7;
H.ERROR_NO_ROOT = 8;
H.ERROR_MATRIX_ARG = 11;
// H.ERROR_DEFECTIVE = 9; // same as 16c, never happens in this simulator
// 12C
H.ERROR_IRR = 3;
H.ERROR_INTEREST = 5;
H.ERROR_MEMORY = 6;
H.ERROR_IRR2 = 7;
H.ERROR_DATE = 8;
// 16C
H.ERROR_IMPROPER_N = 1;
H.ERROR_IMPROPER_BIT = 2;
// H.ERROR_INDEX = 3; // STO register number invalid, same as 11C
// H.ERROR_IP = 4; // same as 11C, 12C
// H.ERROR_RTN = 5 // same as 11C (GOSUB-related error)
H.ERROR_NUMBERFORMAT = 6; // 16C-exclusive, floating point x integer number format
H.ERROR_DEFECTIVE = 9; // same as 15c, never happens in this simulator
H.ERROR_FLAG16 = 1;
H.check_closure_args = function (args)
{
// replaced by actual checking at unittest_main
};
H.make_closure = function (fname, args, asm)
{
H.check_closure_args(args);
var f = function () {
H.machine[fname].apply(H.machine, args);
if (H.machine.program_mode <= H.INTERACTIVE) {
H.dispatcher.log_opcode(asm);
}
};
f.closure_type = "machine";
f.closure_name = fname;
f.reducible = false;
f.no_pgrm = 0;
f.asm = asm;
f.shrink = 0;
return f;
};
H.make_pgrm_closure = function (fname, arg, asm)
{
var f = function () {
if (H.machine.program_mode <= H.INTERACTIVE) {
H.dispatcher.log_opcode(asm);
}
H.pgrm[fname].call(H.pgrm, arg);
};
f.closure_type = "pgrm";
f.closure_name = fname;
f.reducible = false;
f.no_pgrm = 0;
f.asm = asm;
f.shrink = 0;
return f;
};
H.delay = function (f, ms)
{
return window.setTimeout(f, ms);
};
H.cancel_delay = function (handle)
{
return window.clearTimeout(handle);
};
H.periodic = function (f, ms)
{
return window.setInterval(f, ms);
};
H.cancel_periodic = function (handle)
{
return window.clearInterval(handle);
};
H.defer = function (f)
{
return H.delay(f, 0);
};
H.error = function (msg)
{
window.xlog(msg);
};
H.mod_stt = null;
H.modifier_table = function ()
{
if (H.mod_stt) {
return H.mod_stt;
}
var a = [];
a[0] = "";
a[H.FF] = "f";
a[H.GG] = "g";
a[H.STO] = "STO";
a[H.STO2] = "STO★";
a[H.RCL] = "RCL";
a[H.RCL2] = "RCL★";
if (H.type !== "16c") {
a[H.STO_PLUS] = "STO+";
a[H.STO_MINUS] = "STO-";
a[H.STO_TIMES] = "STO×";
a[H.STO_DIVIDE] = "STO÷";
}
a[H.GTO] = "GTO";
a[H.GTO_MOVE] = "GTO★";
// models without RCL g still use as apocryphal key
a[H.RCL_GG] = "RCL g";
if (H.type === "11c" || H.type === "15c") {
a[H.HYP] = "HYP";
a[H.HYPINV] = "HYP-1";
a[H.LBL] = "LBL";
a[H.GSB] = "GSB";
a[H.FIX] = "FIX";
a[H.SCI] = "SCI";
a[H.ENG] = "ENG";
a[H.STO_FF] = "STO f";
a[H.RCL_FF] = "RCL f";
a[H.GG_SF] = "SF";
a[H.GG_CF] = "CF";
a[H.GG_FQUESTION] = "F?";
a[H.STO_PLUS_FF] = "STO+ f";
a[H.STO_MINUS_FF] = "STO- f";
a[H.STO_TIMES_FF] = "STO× f";
a[H.STO_DIVIDE_FF] = "STO÷ f";
}
if (H.type === "10c") {
a[H.FIX] = "FIX";
a[H.SCI] = "SCI";
a[H.ENG] = "ENG";
}
if (H.type === "15c") {
a[H.GTO_DOT] = "GTO★";
a[H.GSB_DOT] = "GSB★";
a[H.LBL_DOT] = "LBL★";
a[H.STO_PLUS_DOT] = "STO+★";
a[H.STO_MINUS_DOT] = "STO-★";
a[H.STO_TIMES_DOT] = "STO×★";
a[H.STO_DIVIDE_DOT] = "STO÷★";
a[H.RCL_PLUS] = "RCL+";
a[H.RCL_MINUS] = "RCL-";
a[H.RCL_TIMES] = "RCL×";
a[H.RCL_DIVIDE] = "RCL÷";
a[H.RCL_PLUS_DOT] = "RCL+★";
a[H.RCL_MINUS_DOT] = "RCL-★";
a[H.RCL_TIMES_DOT] = "RCL×★";
a[H.RCL_DIVIDE_DOT] = "RCL÷★";
a[H.RCL_PLUS_FF] = "STO+ f";
a[H.RCL_MINUS_FF] = "STO- f";
a[H.RCL_TIMES_FF] = "STO× f";
a[H.RCL_DIVIDE_FF] = "STO÷ f";
a[H.FF_EXCHANGE] = "X⇄";
a[H.FF_EXCHANGE_DOT] = "X⇄★";
a[H.SOLVE] = "SOLV";
a[H.SOLVE_DOT] = "SOLV★";
a[H.INTEG] = "INTG";
a[H.INTEG_DOT] = "INTG★";
a[H.GG_TEST] = "TEST";
a[H.DIM] = "DIM";
a[H.RCL_DIM] = "RCL D";
a[H.MATRIX] = "M";
a[H.STO_GG] = "STO g";
a[H.STO_MATRIX] = "STO M";
a[H.STO_FF_MATRIX] = "STO M";
a[H.RCL_MATRIX] = "RCL M";
a[H.RCL_FF_MATRIX] = "RCL M";
a[H.RESULT] = "Res";
a[H.ISG] = "ISG";
a[H.ISG_DOT] = "ISG★";
a[H.DSE] = "DSE";
a[H.DSE_DOT] = "DSE★";
}
if (H.type === "16c") {
a[H.LBL] = "LBL";
a[H.GSB] = "GSB";
a[H.GG_SF] = "SF";
a[H.GG_CF] = "CF";
a[H.GG_FQUESTION] = "F?";
a[H.STO_FF] = "STO f";
a[H.RCL_FF] = "RCL f";
a[H.WINDOW] = "WINDOW";
a[H.FLOAT] = "FLOAT";
}
H.mod_stt = a;
return H.mod_stt;
};
H.MODAL_NONE = 0;
H.MODAL_PAUSE = 1;
H.MODAL_PRESS = 2;
H.MODAL_MISC = 3;
H.MODAL_ERROR = 4;
/*jslint white: true, undef: true, nomen: true, regexp: true, bitwise: true, strict: true, browser: true, bitwise: true */
/*jshint globalstrict: true*/
/*global H */
"use strict";
function Hp12c_debug(format_result)
{
var self = this;
self.memwin = null;
self.format_result = format_result;
}
Hp12c_debug.prototype.format_result_i = function (t)
{
var self = this;
var it = {r: t.i, i: t.r, h: t.h};
return self.format_result(it);
};
Hp12c_debug.prototype.format_matrix = function (t)
{
var self = this;
var size = H.machine.matrix_size(t.r);
return "Mat " +
(10 + t.r - 20).toString(16).toUpperCase() +
" (" + size[0] + "x" + size[1] + ")";
};
Hp12c_debug.prototype.show_memory2 = function ()
{
var self = this;
if (! self.memwin || ! self.memwin.document) {
// window has been closed; don't schedule updates anymore
self.memwin = null;
return;
}
var windoc = self.memwin.document;
var now = new Date();
var title = windoc.getElementById('tt');
var e;
if (title) {
title.innerHTML = H.type + " memory at " + now;
if (H.is_12c()) {
for (e = 0; e < H.machine.finmemory.length; ++e) {
windoc.getElementById("finmemory" + e).innerHTML =
self.format_result({r: H.machine.finmemory[e]});
}
}
for (e = 0; e < H.machine.stomemory.length; ++e) {
var elem = windoc.getElementById("stomemory" + e);
if (! elem && e >= 32) {
// pardon (16c has *lots* of memory)
continue;
}
elem.innerHTML =
self.format_result(H.machine.sto_tuple(e));
}
if (H.is_12c()) {
for (e = 0; e < H.machine.njmemory.length; ++e) {
windoc.getElementById("njmemory" + e).innerHTML =
self.format_result({r: H.machine.njmemory[e]});
}
}
if (H.machine.matrix_in_reg("x")) {
windoc.getElementById("x").innerHTML =
self.format_matrix(H.machine.reg_tuple("x"));
windoc.getElementById("xi").innerHTML = "";
} else {
windoc.getElementById("x").innerHTML =
self.format_result(H.machine.reg_tuple("x"));
if (H.type === "15c") {
windoc.getElementById("xi").innerHTML =
self.format_result_i(H.machine.reg_tuple("x"));
}
}
if (H.machine.matrix_in_reg("last_x")) {
windoc.getElementById("last_x").innerHTML =
self.format_matrix(H.machine.reg_tuple("last_x"));
windoc.getElementById("last_xi").innerHTML = "";
} else {
windoc.getElementById("last_x").innerHTML =
self.format_result(H.machine.reg_tuple("last_x"));
if (H.type === "15c") {
windoc.getElementById("last_xi").innerHTML =
self.format_result_i(H.machine.reg_tuple("last_x"));
}
}
if (H.machine.matrix_in_reg("y")) {
windoc.getElementById("y").innerHTML =
self.format_matrix(H.machine.reg_tuple("y"));
windoc.getElementById("yi").innerHTML = "";
} else {
windoc.getElementById("y").innerHTML =
self.format_result(H.machine.reg_tuple("y"));
if (H.type === "15c") {
windoc.getElementById("yi").innerHTML =
self.format_result_i(H.machine.reg_tuple("y"));
}
}
if (H.machine.matrix_in_reg("z")) {
windoc.getElementById("z").innerHTML =
self.format_matrix(H.machine.reg_tuple("z"));
windoc.getElementById("zi").innerHTML = "";
} else {
windoc.getElementById("z").innerHTML =
self.format_result(H.machine.reg_tuple("z"));
if (H.type === "15c") {
windoc.getElementById("zi").innerHTML =
self.format_result_i(H.machine.reg_tuple("z"));
}
}
if (H.machine.matrix_in_reg("w")) {
windoc.getElementById("w").innerHTML =
self.format_matrix(H.machine.reg_tuple("w"));
windoc.getElementById("wi").innerHTML = "";
} else {
windoc.getElementById("w").innerHTML =
self.format_result(H.machine.reg_tuple("w"));
if (H.type === "15c") {
windoc.getElementById("wi").innerHTML =
self.format_result_i(H.machine.reg_tuple("w"));
}
}
if (H.type === "11c" || H.type === "15c" || H.type === "16c") {
if (H.machine.matrix_in_index()) {
windoc.getElementById("index").innerHTML =
self.format_matrix({r: H.machine.index,
h: H.machine.indexh,
i: 0});
} else {
windoc.getElementById("index").innerHTML =
self.format_result({r: H.machine.index, h: 0, i: 0});
}
}
for (e = 0; e < H.machine.ram.length; ++e) {
var opcode = H.machine.ram[e];
var asm = H.pgrm.disassemble(opcode);
var txt = "";
if (opcode && asm !== "NOP") {
txt = H.pgrm.disassemble(opcode) +
" (" + opcode + ")";
}
windoc.getElementById("ram" + e).innerHTML = txt;
}
}
H.delay(function () {
self.show_memory2();
}, 1000);
};
Hp12c_debug.prototype.show_memory = function ()
{
var self = this;
self.memwin = window.open(H.type_cookie + '_memory.html');
H.delay(function () {
self.show_memory2();
}, 1000);
};
/*jslint white: true, undef: true, nomen: true, regexp: true, strict: true, browser: true, sub: true */
/*jshint globalstrict: true*/
/*global H */
"use strict";
H.display_max = 9999999999;
H.display_len = 10; // without extra -
H.display_min = 0.0000000001;
H.format_result_armored = function (n, decs, notation, co)
{
n = n.r || 0;
if (n > H.value_max) {
n = H.value_max;
} else if (n < -H.value_max) {
n = -H.value_max;
} else if (Math.abs(n) < H.value_min) {
n = 0;
}
return H.format_result(n, decs, notation, co);
};
// called by unit tests
H.format_result_ut = function (n)
{
return H.format_result(n, H.machine.decimals, H.machine.notation, H.machine.comma);
};
// called by copy to clipboard
H.format_result_clipboard = function ()
{
var t = H.machine.reg_tuple("x");
var notation = H.machine.notation;
if (notation < H.NOTATION_INT) {
var co = false;
var decs = H.machine.decimals;
var txt = H.trim(H.format_result(t.r, decs, notation, co, true));
txt = txt.replace(/ +/g, 'e');
return txt;
}
var negative_repr = H.machine.negative_repr;
var wordsize = H.machine.wordsize;
return H.format_result_integer(t, notation, negative_repr, wordsize);
};
H.format_result = function (n, decs, notation, co, nosep)
{
var res = "";
var absn = Math.abs(n);
var fix_dec = decs;
var mantissa_dec = decs;
var degenerate = 0;
var scale;
var mantissa;
// bias to make sure that toFixed() rounding is always "up"
// (e.g. 2.5 -> 3, 1.5 -> 2, -2.5 -> -3 for 0 display decimals)
// Appropriate for number 0 < n < 9.999; needs scaling for bigger numbers
var bias = 0.000000000001;
if (n >= H.value_max) {
degenerate = 1;
scale = 99;
n = H.value_max;
absn = Math.abs(n);
} else if (n <= -H.value_max) {
degenerate = 2;
scale = 99;
n = -H.value_max;
absn = Math.abs(n);
} else if (absn >= H.value_min) {
scale = Math.log(absn) / Math.log(10);
// added a tad to guarantee that log(10) === 1
scale = Math.floor(scale + 0.00000000001);
} else {
degenerate = 3;
scale = -100;
absn = n = 0;
}
if (notation == H.NOTATION_FIX) {
// note that 12C and 16C are hardwired to FIX
if (H.type === "15c" || H.type === "11c" || H.type === "10c") {
} else {
// 12C, 16C: show all decimals we can if SCI mode
mantissa_dec = 6;
}
if (absn > H.display_max) {
// too big to be shown normally
notation = H.NOTATION_SCI;
} else if (absn !== 0 && scale < -9) {
// too small to be shown at all
notation = H.NOTATION_SCI;
} else if (absn !== 0 && fix_dec < (-scale)) {
// too small to be shown with current decimal count
if (H.type === "15c" || H.type === "11c" || H.type === "10c") {
// change to SCI
notation = H.NOTATION_SCI;
} else {
// 12C, 16C
// we need more decimals to show this number
fix_dec = -scale;
}
}
}
mantissa_dec = Math.min(mantissa_dec, 6);
if (degenerate != 3) {
mantissa = n / Math.pow(10, scale);
} else {
mantissa = 0;
}
// handle rounding up
var mantissa_signal = mantissa >= 0 ? 1 : -1;
mantissa = parseFloat((Math.abs(mantissa) + (mantissa !== 0 ? bias : 0)).toFixed(mantissa_dec));
if (notation != H.NOTATION_FIX && mantissa >= 10) {
mantissa /= 10;
scale += 1;
}
// give signal back
mantissa *= mantissa_signal;
// until now, ENG handling == SCI
// now, compensate for ENG
if (notation == H.NOTATION_ENG && (! degenerate)) {
var new_scale = 3 * Math.floor(scale / 3);
while (scale > new_scale) {
mantissa *= 10;
scale -= 1;
if (mantissa_dec > 0) {
mantissa_dec -= 1;
}
}
}
if (notation !== H.NOTATION_FIX) {
// show as exponential
/*
if (mantissa === 0 && (H.type !== "11c" && H.type !== "15c") && false) {
// in SCI mode, 12C shows 0.0000000 00 too...
return H.i18n(' 0', co, 1, false, nosep);
*/
if (degenerate == 1) {
return H.i18n(' 9.999999 99', co, 1, false, nosep);
} else if (degenerate == 2) {
return H.i18n('-9.999999 99', co, 1, false, nosep);
}
res = H.i18n((mantissa + (mantissa > 0 ? bias : (mantissa < 0 ? -bias : 0)))
.toFixed(mantissa_dec), co, 1, false, nosep);
if (mantissa >= 0) {
res = " " + res;
}
// no need to compensate for thousand separators because even
// in ENG mode mantissa is < 1000.
// display_len does NOT count the negative sign
// -3: exponential plus space/expo signal
// +1: compressed decimal point (always present, even if mantissa_dec == 0)
// +1: negative sign
var max_m_len = H.display_len - 3 + 1 + 1;
res = res.substr(0, max_m_len);
while (res.length < max_m_len) {
res = res + " ";
}
if (mantissa === 0) {
scale = 0;
}
if (scale < 0) {
res = res + "-" + H.zeropad((-scale).toFixed(0), 2);
} else {
res = res + " " + H.zeropad(scale.toFixed(0), 2);
}
// window.xlog(" " + n + " " + mantissa + " " + scale + " d " + degenerate + " " + res);
return res;
}
// show as FIX
if (absn >= 10) {
bias *= absn;
}
var dec = Math.max(0, fix_dec);
var sgn = n < 0 ? "-" : " ";
n = absn;
var ll = (n + (n !== 0 ? bias : 0)).toFixed(dec).length - (dec > 0 ? 1 : 0);
if (ll > H.display_len) {
// reduce decimals if too big for display
dec -= (ll - H.display_len);
dec = Math.max(0, dec);
}
res = H.i18n(sgn + (n + (n !== 0 ? bias : 0)).toFixed(dec), co, 1, false, nosep);
return res;
};
H.format_result_integer = function (t, notation, negative_repr, wordsize)
{
var radix = H.get_radix(notation)[0];
return H.format_integer_to_string(t, radix, negative_repr, wordsize);
};
// used only for debugging purposes, so it may use H.machine
H.format_result_tuple = function (t)
{
var notation = H.machine.notation;
if (notation < H.NOTATION_INT) {
var co = H.machine.comma;
var decs = H.machine.decimals;
return H.format_result(t.r, decs, notation, co);
}
var negative_repr = H.machine.negative_repr;
var wordsize = H.machine.wordsize;
return H.format_result_integer(t, notation, negative_repr, wordsize);
};
H.format_integer = function (x, xmode, typed_digits, altdisplay, notation, wordsize,
digit_max, intwindow, zeros_flag, co, negative_repr)
{
var typing = xmode > -100; // -100, -1, 0
var point1 = "";
var point2 = "";
var sign = " ";
var show_apocryphal = (altdisplay > 0);
var radix = H.get_radix(notation);
var suffix = radix[1];
radix = radix[0];
var spure = H.format_integer_to_string(x, radix, negative_repr, wordsize);
var spure16;
if (radix === 2) {
spure16 = H.format_integer_to_string(x, 16, negative_repr, wordsize);
}
// window.xlog(spure);
if (spure.substr(0, 1) === "-") {
spure = spure.substr(1);
sign = "-";
}
var s, sfull;
var len = 8;
var bits_per_digit = H.digit_bits[notation];
var digits_on_display = H.disp_digits[notation];
var tot_digits = Math.ceil(wordsize / bits_per_digit);
var tot_digits_ceil = digit_max;
var si2 = spure;
var significant_digits = si2.length;
if (typing) {
while (si2.length < typed_digits) {
si2 = "0" + si2;
}
}
var current_window = typing ? 0 : intwindow;
show_apocryphal = show_apocryphal &&
((significant_digits > digits_on_display) ||
(current_window > 0));
var filler = " ";
if (zeros_flag && radix !== 10) {
filler = "0";
}
while (si2.length < tot_digits) {
si2 = filler + si2;
}
while (si2.length < tot_digits_ceil) {
si2 = " " + si2;
}
if (current_window > 0) {
point2 = ".";
}
if (current_window < (significant_digits - digits_on_display)) {
point1 = ".";
}
// window cutting
var dpos = tot_digits_ceil - current_window - digits_on_display;
// console.log("FIXME dpos " + dpos + " tot_digits_ceil " + tot_digits_ceil + " current_window " + current_window + " digitson_display " + digits_on_display);
// console.log("FIXME " + si2);
si2 = si2.substr(dpos, digits_on_display);
dpos = current_window;
var lcdsign = sign;
if (radix === 10) {
var sp = si2.lastIndexOf(" ");
if (sp >= 0) {
si2 = si2.substr(0, sp) + lcdsign + si2.substr(sp + 1);
lcdsign = " ";
} else if (point1 === ".") {
// next window has significant digits
// do not show LCD sign
lcdsign = " ";
} else {
// this window is full but next window does not
// have significant digits
// leave LCD sign in place
}
}
// if window > 0, i18n() might put decimal places
// in wrong values, because si2 has been cut. We add zeros as
// LSBs until the LSB is a multiple of 3 or 4, so i18n(si2) does well.
var r10comp = 0;
var modulus = (radix === 10) ? 3 : 4;
while (((dpos - r10comp) % modulus) > 0) {
si2 += "0";
r10comp++;
}
si2 = H.i18n(si2, co, 0, radix !== 10);
// Remove LSB compensation
if (r10comp > 0) {
si2 = si2.substr(0, si2.length - r10comp);
}
s = lcdsign + si2 + " " + point1 + suffix + point2;
sfull = sign + (radix === 2 ? spure16 : spure);
sfull = H.i18n(sfull, co, 0, radix !== 10);
return [s, sfull, show_apocryphal];
};
H.html_wrap = function (txt) {
var j = 0;
var c;
for (var i = 0; i < txt.length; ++i) {
c = txt.charAt(i);
++j;
if (j > 13 || (j > 9 && (c === "." || c === ","))) {
txt = txt.substr(0, i + 1) + "
" + txt.substr(i + 1);
i += 4;
j = 0;
}
}
return txt;
};
H.format_matrix = function (n, r, c)
{
var s = " " + (10 + n - 20).toString(16).toUpperCase() +
" " + r + ", " + c;
return s;
};
H.format_typed_number = function (ms, m, dec, exp, exps, xmode, co, notation, decs)
{
if (m.length === 0) {
// nothing typed, or BSP'ed to none
return H.format_result(0, decs, notation, co);
}
var s = "";
if (xmode === 0) {
s = " 0";
if (m.length > 0) {
s = (ms < 0 ? "-" : " ") + m;
}
if (H.type !== "11c" && H.type !== "15c" && H.type !== "10c") {
s += ".";
}
s = H.i18n(s, co, 0);
} else if (xmode === 1) {
s = H.i18n((ms < 0 ? "-" : " ") + m + "." + dec, co, 1);
} else if (xmode === 100) {
var rdec = dec.substr(0, 7 - m.length);
s = H.i18n((ms < 0 ? "-" : " ") + m + "." + rdec, co, 1);
for (var i = 0; i < (7 - rdec.length - m.length); ++i) {
s += " ";
}
s += exps < 0 ? "-" : " ";
s += H.zeropad(parseInt("0" + exp, 10).toFixed(0), 2);
}
return s;
};
H.get_radix = function (notation)
{
var radix = H.radix[notation];
var suffix = H.radix_suffix[notation];
return [radix, suffix];
};
H.format_integer_to_string = function (t, radix, pnegative_repr, wordsize)
{
// for non-decimal, how as unsigned
var negative_repr = 0;
if (radix === 10) {
negative_repr = pnegative_repr;
}
var spure = H.integer_to_string(t,
negative_repr,
wordsize,
radix,
true);
return spure;
};
/*jslint white: true, undef: true, nomen: true, regexp: true, strict: true, browser: true, sub: true */
/*jshint globalstrict: true*/
/*global H */
"use strict";
function Hp12c_display()
{
var self = this;
self.lcd = [];
// contents that "should be" on screen. Closure or list of strings
self.contents_logical = ["", ""];
// contents that are actually on screen e.g. could be "" when flickering
self.contents_physical = "replaceme";
self.contents_alt_physical = "replaceme";
// contents that "should be" and are actually in modifier
self.contents_modifier_logical = "";
self.contents_modifier_physical = "replaceme";
// LCD fast 'flicker' when a key is pressed
self.flicker_delay = 25;
self.flicker_timer = null;
// LCD continuous blink when overflow
self.overflow_blink = false;
self.overflow_blink_timer = null;
self.overflow_blink_freq = 250; // ms
var LCD_A = 1;
var LCD_B = 2;
var LCD_C = 4;
var LCD_D = 8;
var LCD_E = 16;
var LCD_F = 32;
var LCD_G = 64;
var LCD_P = 128;
var LCD_T = 256;
self.lcdmap = [];
self.lcdmap['0'] = LCD_A | LCD_B | LCD_C | LCD_E | LCD_F | LCD_G;
self.lcdmap['1'] = LCD_C | LCD_F;
self.lcdmap['2'] = LCD_A | LCD_C | LCD_D | LCD_E | LCD_G;
self.lcdmap['3'] = LCD_A | LCD_C | LCD_D | LCD_F | LCD_G;
self.lcdmap['4'] = LCD_B | LCD_C | LCD_D | LCD_F;
self.lcdmap['5'] = LCD_A | LCD_B | LCD_D | LCD_F | LCD_G;
self.lcdmap['6'] = LCD_A | LCD_B | LCD_D | LCD_E | LCD_F | LCD_G;
self.lcdmap['7'] = LCD_A | LCD_C | LCD_F;
self.lcdmap['8'] = LCD_A | LCD_B | LCD_C | LCD_D | LCD_E | LCD_F | LCD_G;
self.lcdmap['9'] = LCD_A | LCD_B | LCD_C | LCD_D | LCD_F | LCD_G;
self.lcdmap[' '] = 0;
self.lcdmap['.'] = LCD_P;
self.lcdmap[','] = LCD_P | LCD_T;
self.lcdmap['r'] = LCD_A | LCD_B;
self.lcdmap['U'] = LCD_B | LCD_C | LCD_E | LCD_F | LCD_G;
self.lcdmap['u'] = LCD_B | LCD_C | LCD_D;
self.lcdmap['n'] = LCD_B | LCD_C | LCD_A;
self.lcdmap['i'] = LCD_B;
self.lcdmap['g'] = LCD_A | LCD_B | LCD_C | LCD_D | LCD_F | LCD_G;
self.lcdmap['-'] = LCD_D;
self.lcdmap['A'] = LCD_A | LCD_B | LCD_C | LCD_D | LCD_E | LCD_F;
self.lcdmap['a'] = self.lcdmap['A'];
self.lcdmap['B'] = LCD_B | LCD_D | LCD_E | LCD_F | LCD_G;
self.lcdmap['b'] = self.lcdmap['B'];
self.lcdmap['c'] = LCD_D | LCD_E | LCD_G;
self.lcdmap['C'] = self.lcdmap['c'];
self.lcdmap['d'] = LCD_C | LCD_D | LCD_E | LCD_F | LCD_G;
self.lcdmap['D'] = self.lcdmap['d'];
self.lcdmap['E'] = LCD_A | LCD_B | LCD_D | LCD_E | LCD_G;
self.lcdmap['e'] = self.lcdmap['E'];
self.lcdmap['F'] = LCD_A | LCD_B | LCD_D | LCD_E;
self.lcdmap['f'] = self.lcdmap['F'];
self.lcdmap['H'] = LCD_B | LCD_C | LCD_D | LCD_E | LCD_F;
self.lcdmap['h'] = LCD_B | LCD_D | LCD_E | LCD_F;
self.lcdmap['o'] = LCD_D | LCD_E | LCD_F | LCD_G;
self.lcdmap['O'] = self.lcdmap["o"];
self.lcdmap['R'] = LCD_D | LCD_E;
self.lcdmap['P'] = LCD_A | LCD_B | LCD_C | LCD_D | LCD_E;
self.lcdmap[':'] = LCD_P;
for (var e = 0; e <= 10; ++e) {
self.lcd[e] = [];
self.lcd[e][0] = 0;
self.lcd[e][self.lcd[e].length] = H.getElem("lcd" + e + "a");
self.lcd[e][self.lcd[e].length] = H.getElem("lcd" + e + "b");
self.lcd[e][self.lcd[e].length] = H.getElem("lcd" + e + "c");
self.lcd[e][self.lcd[e].length] = H.getElem("lcd" + e + "d");
self.lcd[e][self.lcd[e].length] = H.getElem("lcd" + e + "e");
self.lcd[e][self.lcd[e].length] = H.getElem("lcd" + e + "f");
self.lcd[e][self.lcd[e].length] = H.getElem("lcd" + e + "g");
self.lcd[e][self.lcd[e].length] = H.getElem("lcd" + e + "p");
self.lcd[e][self.lcd[e].length] = H.getElem("lcd" + e + "t");
}
self.display = H.getElem("display");
self.dbegin = H.getElem("begin");
self.ddmyc = H.getElem("dmyc");
self.dmodifier = H.getElem("modifier");
self.pgrm = H.getElem("pgrm");
self.rpnalg = H.getElem("rpnalg");
self.trigo = H.getElem("trigo");
self.user = H.getElem("user");
self.carry = H.getElem("carry");
self.overflow = H.getElem("overflow");
self.complex = H.getElem("complex");
self.altdisplay = H.getElem("altdisplay");
self.wordstatus = H.getElem("wordstatus");
self.undo = H.getElem("undo");
self.parentheses = H.getElem("parentheses");
self.clear();
}
Hp12c_display.prototype.private_show = function (dummy)
{
// This method only exists because the mobile versions
// override it to detect changes in display, and schedule
// memory saving.
};
// converts contents to LCD segments
Hp12c_display.prototype.physical_lcd_display = function (contents)
{
var self = this;
var txt = contents[0];
var alttxt = contents[1];
self.show_alt(alttxt);
if (self.contents_physical === txt) {
return;
}
// no-op, but mobile versions override method and
// might look the argument
self.private_show(txt);
self.contents_physical = txt;
window.console.ut_snap("lcd ");
var f = -1;
var buffer = [];
for (var e = 0; e < txt.length && f < self.lcd.length; ++e) {
var merge = false;
var val = txt.charAt(e);
++f;
if ((val == '.' || val == ',') && f > 0) {
// merge decimal point/thousand separator
--f;
merge = true;
}
if (! self.lcdmap[val]) {
val = ' ';
}
var map = self.lcdmap[val];
buffer[f] = map | (merge ? buffer[f] : 0);
}
for (++f; f < self.lcd.length; ++f) {
buffer[f] = 0;
}
if (H.embedded) {
self.display.showDisplay(buffer);
return;
}
for (f = 0; f < buffer.length && f < self.lcd.length; ++f) {
var map2 = buffer[f];
for (var segm = 1; segm < 10; ++segm) {
var bit = 1 << (segm - 1);
var visibility = (map2 & bit) ? "visible" : "hidden";
if (self.lcd[f][segm].style.visibility !== visibility) {
self.lcd[f][segm].style.visibility = visibility;
}
}
}
};
Hp12c_display.prototype.set_blink = function (blinks)
{
var self = this;
self.overflow_blink = blinks;
self.recycle();
};
Hp12c_display.prototype.clear = function ()
{
var self = this;
self.new_content(["", ""], false);
self.show_wordstatus("");
};
Hp12c_display.prototype.displayMatrix = function (n, r, c)
{
var self = this;
self.new_content(function () {
return [H.format_matrix(n, r, c), ""];
}, true);
};
Hp12c_display.prototype.p_display_integer = function (x, xmode, typed_digits, flicker)
{
var self = this;
var altdisplay = H.machine.altdisplay;
var notation = H.machine.notation;
var wordsize = H.machine.wordsize;
var digit_max = H.machine.digit_max();
var intwindow = H.machine.intwindow;
var zeros_flag = H.machine.get_zeros_flag();
var co = H.machine.comma;
var negative_repr = H.machine.negative_repr;
var f = function () {
var res = H.format_integer(x, xmode, typed_digits, altdisplay, notation, wordsize,
digit_max, intwindow, zeros_flag, co, negative_repr);
var s = res[0];
var sfull = res[1];
var show_apocryphal = res[2];
return [s, (show_apocryphal ? H.html_wrap(sfull) : "")];
};
self.new_content(f, flicker);
};
Hp12c_display.prototype.displayNumber = function (x)
{
var self = this;
if (H.type === "16c" && H.machine.notation >= H.NOTATION_INT) {
self.p_display_integer(x, -100, null, true);
return;
}
var decs = H.machine.decimals;
var notation = H.machine.notation;
var co = H.machine.comma;
var f = function () {
var sres = H.format_result_armored(x, decs, notation, co);
return [sres, ""];
};
self.new_content(f, true);
};
Hp12c_display.prototype.displayTypedNumber_integer = function (val, xmode, digits)
{
var self = this;
self.p_display_integer(val, xmode, digits, false);
};
Hp12c_display.prototype.displayTypedNumber = function (ms, m, dec, exp, exps, xmode, notation)
{
var self = this;
var co = H.machine.comma;
var decs = H.machine.decimals;
var f = function () {
var s = H.format_typed_number(ms, m, dec, exp, exps, xmode, co, notation, decs);
return [s, ""];
};
self.new_content(f, false); // no flicker
};
// Show free/unknown contents
Hp12c_display.prototype.show_nopgrm = function (txt)
{
var self = this;
self.new_content([txt, ""], false);
};
// Show "running"
Hp12c_display.prototype.show_running = function ()
{
var self = this;
self.new_content(["running", ""], false);
};
// Show date
Hp12c_display.prototype.show_date = function (txt)
{
var self = this;
self.new_content([txt, ""], true);
};
// ################## Blink / flicker state machine implementation
// LCD contents have changed
Hp12c_display.prototype.new_content = function (content, to_flicker)
{
var self = this;
var will_flicker = false;
if (content !== null) {
self.contents_logical = content;
// flicker uses H.machine.cli()/sti()
will_flicker = to_flicker && (!!H.machine);
window.console.ut_snap("new ");
} else {
window.console.ut_snap("recy ");
}
if (self.overflow_blink_timer) {
H.cancel_periodic(self.overflow_blink_timer);
self.overflow_blink_timer = null;
}
if (self.flicker_timer) {
H.machine.sti("flicker abrt");
H.cancel_delay(self.flicker_timer);
self.flicker_timer = null;
}
if (H.machine) {
var modal = H.machine.modal();
if (modal === H.MODAL_ERROR) {
will_flicker = false;
// override display contents
self.contents_logical = ["ERROR " + H.machine.error(), ""];
} else if (modal === H.MODAL_PAUSE) {
will_flicker = false;
self.show_modifier_physical("PAUSE");
} else if (modal === H.MODAL_PRESS) {
will_flicker = false;
self.show_modifier_physical("Press");
} else if (modal === H.MODAL_MISC) {
will_flicker = false;
} else if (H.machine.program_mode === H.RUNNING_STEP_PRE) {
will_flicker = false;
self.show_modifier_physical("Press");
} else {
// refresh modifier, in case last mode was modal
self.show_modifier_physical(self.contents_modifier_logical);
if (H.machine.program_mode === H.RUNNING || H.machine.running_context.length > 0) {
if (H.machine.rapid) {
// Show "running" but preserve the logical display content
self.physical_lcd_display(["running", ""]);
// elide display update when in rapid mode
return;
}
will_flicker = false;
}
}
}
var f = function () {
if (self.overflow_blink) {
self.overflow_blink_on = true;
self.overflow_blink_timer =
H.periodic(function () {
self.overflow_blink_on = ! self.overflow_blink_on;
if (self.overflow_blink_on) {
window.console.ut_snap("blink");
self.physical_lcd_display(self.r_contents_logical());
} else {
window.console.ut_snap("blonk");
self.physical_lcd_display(["", ""]);
}
},
self.overflow_blink_freq);
}
self.physical_lcd_display(self.r_contents_logical());
};
if (will_flicker) {
// flicker: clear display for a short while
self.physical_lcd_display(["", ""]);
// block keyboard
H.machine.cli("flicker");
// schedule redisplay (f() block contains overflow blink logic)
self.flicker_timer = H.delay(function () {
self.flicker_timer = null;
H.machine.sti("flicker");
f();
}, self.flicker_delay);
} else {
f();
}
};
Hp12c_display.prototype.recycle = function () {
var self = this;
self.new_content(null);
};
Hp12c_display.prototype.r_contents_logical = function ()
{
var self = this;
if (typeof self.contents_logical === "function") {
// resolve lazy evaluation
self.contents_logical = self.contents_logical();
}
return self.contents_logical;
};
// ############################################ Modifier
Hp12c_display.prototype.show_modifier = function (m)
{
var self = this;
var txt = H.modifier_table()[m];
if (txt === undefined || txt === null) {
H.error("Display: unknown modifier " + m);
txt = "";
}
self.contents_modifier_logical = txt;
// do not change modifier in modal state (PAUSE or Press are painted there)
// or when running in rapid mode (to save processing time)
var modal = H.machine.modal() > 0 || H.machine.program_mode === H.RUNNING_STEP_PRE;
var running_rapid = H.machine.rapid &&
(H.machine.program_mode === H.RUNNING || H.machine.running_context.length > 0);
if (modal || running_rapid) {
return;
}
self.show_modifier_physical(txt);
};
// ################## Annunciators and other 'simple' elements
Hp12c_display.prototype.show_dmyc = function (dmy, compoundf)
{
var self = this;
var txt = "";
if (dmy) {
txt += "D.MY";
}
if (compoundf) {
txt += " C";
}
self.setInnerHTML("ddmyc", txt);
};
Hp12c_display.prototype.show_modifier_physical = function (txt)
{
var self = this;
if (txt !== self.contents_modifier_physical) {
self.contents_modifier_physical = txt;
self.setInnerHTML("dmodifier", self.contents_modifier_physical);
window.console.ut_snap("mod ");
}
};
Hp12c_display.prototype.show_pgrm = function (pgrm, run, pc)
{
var self = this;
var txt = "";
if (pgrm) {
txt = "PRGM";
} else if (run) {
txt = "RUN " + H.zeropad(pc.toFixed(0), 2);
}
self.setInnerHTML("pgrm", txt);
};
Hp12c_display.prototype.show_algmode = function (algmode)
{
var self = this;
if (H.type === "12c-platinum") {
var txt = ["RPN", "ALG"][algmode];
self.setInnerHTML("rpnalg", txt);
}
};
Hp12c_display.prototype.show_trigo = function (trigo)
{
var self = this;
if (H.type === "11c" || H.type === "15c" || H.type === "10c") {
var txt = ["", "RAD", "GRAD"][trigo];
self.setInnerHTML("trigo", txt);
}
};
Hp12c_display.prototype.show_user = function (user)
{
var self = this;
if (H.type === "11c" || H.type === "15c") {
var txt = ["", "USER"][user];
self.setInnerHTML("user", txt);
}
};
Hp12c_display.prototype.setInnerHTML = function (name, txt)
{
var self = this;
if (H.embedded) {
self.display.setInnerHTML(name, txt);
} else {
var tgt = self[name];
if (tgt) {
tgt.innerHTML = txt;
}
}
};
Hp12c_display.prototype.show_carry = function (is_carry)
{
var self = this;
var txt = "";
if (is_carry) {
txt = "C";
}
if (H.type === "16c") {
self.setInnerHTML("carry", txt);
}
};
Hp12c_display.prototype.show_overflow = function (is_overflow)
{
var self = this;
var txt = "";
if (is_overflow) {
txt = "G";
}
if (H.type === "16c") {
self.setInnerHTML("overflow", txt);
}
};
Hp12c_display.prototype.show_begin = function (is_begin)
{
var self = this;
var txt = "";
if (is_begin) {
txt = "BEGIN";
}
self.setInnerHTML("dbegin", txt);
};
Hp12c_display.prototype.show_alt = function (txt)
{
var self = this;
if (self.contents_alt_physical === txt) {
return;
}
self.contents_alt_physical = txt;
self.setInnerHTML("altdisplay", txt);
window.console.ut_snap("alth ");
};
Hp12c_display.prototype.show_wordstatus = function (txt)
{
var self = this;
self.setInnerHTML("wordstatus", txt);
};
Hp12c_display.prototype.show_parentheses = function (txt)
{
var self = this;
self.setInnerHTML("parentheses", txt);
};
Hp12c_display.prototype.show_undo = function (enabled)
{
var self = this;
self.setInnerHTML("undo", enabled ? "u" : "");
};
Hp12c_display.prototype.show_complex = function (is_complex)
{
var self = this;
var txt = "";
if (is_complex) {
txt = "C";
}
if (H.type === "15c") {
self.setInnerHTML("complex", txt);
}
};
/*jslint white: true, undef: true, nomen: true, regexp: true, strict: true, browser: true, sub: true, bitwise: true */
/*jshint globalstrict: true*/
/*global H */
"use strict";
function Hp12c_keyboard()
{
var self = this;
self.is_enabled = 0;
self.buffer = 0;
self.kbdtable = {};
self.kbdtable['0'] = 0;
self.kbdtable['.'] = 48;
self.kbdtable[','] = 48;
self.kbdtable['1'] = 1;
self.kbdtable['2'] = 2;
self.kbdtable['3'] = 3;
self.kbdtable['4'] = 4;
self.kbdtable['5'] = 5;
self.kbdtable['6'] = 6;
self.kbdtable['7'] = 7;
self.kbdtable['8'] = 8;
self.kbdtable['9'] = 9;
self.kbdtable['+'] = 40;
self.kbdtable['='] = 40;
self.kbdtable['-'] = 30;
self.kbdtable['*'] = 20;
self.kbdtable['x'] = 20;
self.kbdtable['X'] = 20;
self.kbdtable['/'] = 10;
self.kbdtable[':'] = 10;
self.kbdtable['\r'] = 36;
self.kbdtable['\n'] = 36;
self.kbdtable[' '] = 36;
self.kbdtable['f'] = 42;
self.kbdtable['F'] = 42;
self.kbdtable['g'] = 43;
self.kbdtable['G'] = 43;
self.kbdtable['s'] = 44;
self.kbdtable['S'] = 44;
self.kbdtable['r'] = 45;
self.kbdtable['R'] = 45;
self.kbdtable['o'] = 41;
self.kbdtable['O'] = 41;
H.hp1xc_keyboard_flavor(self.kbdtable);
// stay here while vertical map translation is uniform across models
self.vertical_map = {};
self.vertical_map[0] = -1;
self.vertical_map[1] = 11;
self.vertical_map[2] = 12;
self.vertical_map[3] = 13;
self.vertical_map[4] = 14;
self.vertical_map[5] = 15;
self.vertical_map[10] = -1;
self.vertical_map[11] = 21;
self.vertical_map[12] = 22;
self.vertical_map[13] = 23;
self.vertical_map[14] = 24;
self.vertical_map[15] = 25;
self.vertical_map[20] = 41;
self.vertical_map[21] = 31;
self.vertical_map[22] = 32;
self.vertical_map[23] = 33;
self.vertical_map[24] = 34;
self.vertical_map[25] = 35;
self.vertical_map[30] = 45;
self.vertical_map[31] = 16;
self.vertical_map[32] = 7;
self.vertical_map[33] = 8;
self.vertical_map[34] = 9;
self.vertical_map[35] = 10;
self.vertical_map[40] = 44;
self.vertical_map[41] = 26;
self.vertical_map[42] = 4;
self.vertical_map[43] = 5;
self.vertical_map[44] = 6;
self.vertical_map[45] = 20;
self.vertical_map[50] = 43;
self.vertical_map[51] = 36;
self.vertical_map[52] = 1;
self.vertical_map[53] = 2;
self.vertical_map[54] = 3;
self.vertical_map[55] = 30;
self.vertical_map[60] = 42;
self.vertical_map[61] = 36;
self.vertical_map[62] = 0;
self.vertical_map[63] = 48;
self.vertical_map[64] = 49;
self.vertical_map[65] = 40;
self.kbdcoord = {};
self.kbdcoord[11] = 0;
self.kbdcoord[12] = 1;
self.kbdcoord[13] = 2;
self.kbdcoord[14] = 3;
self.kbdcoord[15] = 4;
self.kbdcoord[16] = 5;
self.kbdcoord[7] = 6;
self.kbdcoord[8] = 7;
self.kbdcoord[9] = 8;
self.kbdcoord[10] = 9;
self.kbdcoord[21] = 10;
self.kbdcoord[22] = 11;
self.kbdcoord[23] = 12;
self.kbdcoord[24] = 13;
self.kbdcoord[25] = 14;
self.kbdcoord[26] = 15;
self.kbdcoord[4] = 16;
self.kbdcoord[5] = 17;
self.kbdcoord[6] = 18;
self.kbdcoord[20] = 19;
self.kbdcoord[31] = 20;
self.kbdcoord[32] = 21;
self.kbdcoord[33] = 22;
self.kbdcoord[34] = 23;
self.kbdcoord[35] = 24;
self.kbdcoord[36] = 25;
self.kbdcoord[1] = 26;
self.kbdcoord[2] = 27;
self.kbdcoord[3] = 28;
self.kbdcoord[30] = 29;
self.kbdcoord[41] = 30;
self.kbdcoord[42] = 31;
self.kbdcoord[43] = 32;
self.kbdcoord[44] = 33;
self.kbdcoord[45] = 34;
// ENTER is 36
self.kbdcoord[0] = 36;
self.kbdcoord[48] = 37;
self.kbdcoord[49] = 38;
self.kbdcoord[40] = 39;
H.hp1xc_vertical_keyboard_flavor(self.vertical_map);
self.kbdcoordv = {};
for (var opcode in self.kbdcoord) {
if (self.kbdcoord.hasOwnProperty(opcode)) {
// do reverse translation on vertical_map[coord] -> opcode
// (given opcode, find key)
for (var vcoord in self.vertical_map) {
if (self.vertical_map.hasOwnProperty(vcoord)) {
var vopcode = self.vertical_map[vcoord];
if (opcode == vopcode) {
self.kbdcoordv[opcode] = vcoord;
}
}
}
}
}
self.pointer_div = H.getElem("pointer_div");
/* kludge to fix wrong use of offsetLeft, offsetTop later on */
self.adcontainer = H.getElem("adcontainer");
if (! self.adcontainer) {
self.adcontainer = {};
self.adcontainer.offsetLeft = 0;
self.adcontainer.offsetTop = 0;
}
self.cross = H.getElem("cross");
self.css3 = self.has_css3(self.pointer_div);
self.overlays = [];
self.overlays_timer = null;
// recalculate keyboard coordinates
// based on original ones for 700x438 image
if (! H.embedded) {
self.pointer_div_width = parseInt(self.pointer_div.style.width, 10);
self.pointer_div_height = parseInt(self.pointer_div.style.height, 10);
self.kx = self.pointer_div_width / H.disp_theo_width;
self.ky = self.pointer_div_height / H.disp_theo_height;
self.highlight_radius = "" + Math.floor(5 / 600 * self.pointer_div_width) + "px";
}
self.microsoft = (window.navigator && window.navigator.msPointerEnabled && true);
H.touch_display = H.touch_display || self.microsoft;
if (! H.touch_display) {
// Web version running in mobile fare better with touch events
if (self.cross['ontouchstart'] !== undefined) {
H.touch_display = true;
}
}
if (H.touch_display) {
if (self.microsoft) {
var handler = function (x) {
self.mouse_click(x);
};
window.cross.addEventListener("MSPointerDown", handler, true);
} else {
self.cross.ontouchstart = function (x) {
self.mouse_click(x);
};
}
} else {
self.cross.onclick = function (x) {
self.mouse_click(x);
};
}
self.pointer_div.onkeypress = function (x) {
self.hard_keyboard(x);
};
}
Hp12c_keyboard.prototype.enable = function ()
{
var self = this;
self.is_enabled = 1;
// window.xlog("kbd enabled ");
if (self.buffer) {
var key = self.buffer;
self.buffer = 0;
H.defer(function () {
self.do_dispatch_key(key);
});
}
};
Hp12c_keyboard.prototype.disable = function ()
{
var self = this;
self.is_enabled = 0;
// window.xlog("kbd disabled ");
};
Hp12c_keyboard.prototype.enabled = function ()
{
var self = this;
return self.is_enabled;
};
Hp12c_keyboard.prototype.remap_key_vertical = function (raw)
{
var self = this;
var key = -1;
var candidate = self.vertical_map[raw];
if (candidate !== null && candidate !== undefined) {
key = candidate;
}
return key;
};
Hp12c_keyboard.prototype.remap_key = function (raw)
{
var self = this;
// map 'raw' keys to HP12-compatible key codes
var hpkey = raw + 11; // key 0 ("n") becomes key 11
var col = (hpkey % 10); // "n" is at column 1; Divide is at column 0
if (col === 0) {
// "Divide" is not the key 20; it is the key 10
// this operation does NOT change column value
hpkey -= 10;
}
var row = Math.floor(hpkey / 10); // "n" and Device are at line 1
if (hpkey == 47 /* zero */ ) {
hpkey = 0;
} else if (col >= 7 && col <= 9 && hpkey != 48 /* point */ && hpkey != 49 /*sigma+*/) {
// numeric keys: key code is equal to the number it represents
hpkey = col - 3 * (row - 1);
}
if (hpkey == 46) {
// ENTER exception
hpkey = 36;
}
return hpkey;
};
Hp12c_keyboard.prototype.dispatch_key = function (key, force)
{
var self = this;
if (! force && ! self.enabled()) {
self.buffer = key;
return;
}
self.do_dispatch_key(key);
};
Hp12c_keyboard.prototype.do_dispatch_key = function (key)
{
var self = this;
self.buffer = 0;
H.dispatcher.dispatch(key);
};
Hp12c_keyboard.prototype.hard_keyboard = function (e)
{
var self = this;
self.transform_coords();
var keynum;
var keychar;
var numcheck;
if (window.event) {
e = window.event;
keynum = window.event.keyCode;
} else if (e.which) {
keynum = e.which;
} else {
return true;
}
keychar = String.fromCharCode(keynum);
var ret = true;
var kk = self.kbdtable[keychar];
if (kk !== undefined && kk !== null) {
var kco = H.vertical_layout ? self.kbdcoordv[kk] : self.kbdcoord[kk];
if (kco !== undefined && kco !== null) {
self.highlight(kco);
}
self.dispatch_key(kk, false);
e.returnValue = false;
if (e.preventDefault) {
e.preventDefault();
}
ret = false;
}
return ret;
};
Hp12c_keyboard.prototype.transform_coords = function ()
{
var self = this;
// recalculate keyboard coordinates
// based on original ones for 700x438 image
// This needs to be recalculated here because coords can be
// changed by Android at any time
if (H.embedded) {
self.kx = 1;
self.ky = 1;
self.pointer_div_width = H.disp_theo_width;
self.pointer_div_height = H.disp_theo_height;
self.highlight_radius = Math.floor(5 / 600 * H.disp_theo_width);
}
self.xoff = H.disp_key_offset_x * self.kx;
self.yoff = H.disp_key_offset_y * self.ky;
self.xl = H.disp_key_width * self.kx;
self.yl = H.disp_key_height * self.ky;
self.xd = H.disp_key_dist_x * self.kx;
self.yd = H.disp_key_dist_y * self.ky;
if (H.disp_fb_offset_x !== undefined) {
self.xoff_fb = H.disp_fb_offset_x * self.kx;
self.yoff_fb = H.disp_fb_offset_y * self.ky;
self.xl_fb = H.disp_fb_width * self.kx;
self.yl_fb = H.disp_fb_height * self.ky;
}
};
Hp12c_keyboard.prototype.mouse_click = function (evt)
{
var self = this;
if (! evt) {
evt = window.event;
}
self.transform_coords();
var pos_x, pos_y;
if (H.embedded) {
pos_x = evt.X;
pos_y = evt.Y;
} else if (H.touch_display) {
if (! self.microsoft) {
evt.preventDefault();
}
// Browser chooses a CSS transform based on viewport
// and touch events are not automatically translated
var css_scale = 1;
if (self.pointer_div['getBoundingClientRect'] !== undefined) {
css_scale = self.pointer_div.getBoundingClientRect().width / self.pointer_div.offsetWidth;
}
// transformed rect is based on x=0 but y is vertically centered
var css_y = self.pointer_div.offsetHeight * (1 - css_scale) / 2;
if (self.microsoft) {
pos_x = evt.pageX - self.pointer_div.offsetLeft - self.adcontainer.offsetLeft;
pos_y = evt.pageY - self.pointer_div.offsetTop - self.adcontainer.offsetTop;
} else {
pos_x = evt.targetTouches[0].pageX - self.pointer_div.offsetLeft - self.adcontainer.offsetLeft;
pos_y = evt.targetTouches[0].pageY - self.pointer_div.offsetTop - self.adcontainer.offsetTop;
}
// xlog("pos x " + pos_x);
// xlog("CSS scale: " + css_scale);
pos_x /= css_scale;
pos_y -= css_y;
pos_y /= css_scale;
// xlog("pos x' " + pos_x);
} else {
pos_x = (evt.offsetX ? evt.offsetX :
(evt.pageX - self.pointer_div.offsetLeft - self.adcontainer.offsetLeft));
pos_y = (evt.offsetY ? evt.offsetY :
(evt.pageY - self.pointer_div.offsetTop - self.adcontainer.offsetTop));
}
if (pos_y < self.yoff && pos_y >= 0 && pos_x >= 0 && pos_x <= self.pointer_div_width) {
// touched LCD
var leftside = pos_x < (self.pointer_div_width / 2);
var pseudo_key = leftside ? 200 : 201;
self.dispatch_key(pseudo_key, true);
return;
}
pos_x -= self.xoff;
pos_y -= self.yoff;
var key;
var in_key;
if (H.vertical_layout) {
if (pos_x < 0 || pos_y < 0 || pos_x >= self.xd * 6 || pos_y >= self.yd * 7) {
return;
}
key = Math.floor(pos_x / self.xd) + 10 * Math.floor(pos_y / self.yd);
while (pos_x > self.xd) {
pos_x -= self.xd;
}
while (pos_y > self.yd) {
pos_y -= self.yd;
}
in_key = (pos_x < self.xl) && ((pos_y < self.yl) || key == 51);
if (in_key) {
var rkey = self.remap_key_vertical(key);
if (rkey >= 0) {
self.highlight(key);
self.dispatch_key(rkey, false);
}
}
} else {
if (pos_x < 0 || pos_y < 0 || pos_x >= self.xd * 10 || pos_y >= self.yd * 4) {
return;
}
key = Math.floor(pos_x / self.xd) + 10 * Math.floor(pos_y / self.yd);
while (pos_x > self.xd) {
pos_x -= self.xd;
}
while (pos_y > self.yd) {
pos_y -= self.yd;
}
in_key = (pos_x < self.xl) && ((pos_y < self.yl) || key == 25);
if (in_key) {
self.highlight(key);
self.dispatch_key(self.remap_key(key), false);
}
}
};
Hp12c_keyboard.prototype.test = function ()
{
var self = this;
self.transform_coords();
if (! self.css3) {
return;
}
for (var x = 0; x < (H.vertical_layout ? 6 : 10); ++x) {
for (var y = 0; y < (H.vertical_layout ? 7 : 4); ++y) {
var xx = self.xoff + x * self.xd;
var yy = self.yoff + y * self.yd;
var id = "test" + x + y;
// DO NOT CHANGE COLOR NAME without fixing Android first
self.make_div(xx, yy, self.xl, self.yl, self.pointer_div,
id, "red");
xx = self.xoff + x * self.xd + self.xoff_fb;
yy = self.yoff + y * self.yd + self.yoff_fb;
id = "testfb" + x + y;
// DO NOT CHANGE COLOR NAME without fixing Android first
self.make_div(xx, yy, self.xl_fb, self.yl_fb, self.pointer_div,
id, "green");
}
}
self.reset_overlays_timer();
H.machine.fb = 1;
window.xlog("Testing feedback");
};
Hp12c_keyboard.prototype.highlight = function (key)
{
var self = this;
if (! H.machine.fb) {
return;
} else if (! self.css3) {
return;
}
self.reset_overlays_timer();
self.remove_overlays();
var is_enter = false;
if (H.vertical_layout) {
if (key === 61) {
key = 51;
}
is_enter = key === 51;
} else {
if (key === 35) {
key = 25;
}
is_enter = key === 25;
}
var x = key % 10;
var y = Math.floor(key / 10);
var xx = self.xoff + x * self.xd; // + self.xoff_fb;
var yy = self.yoff + y * self.yd; // + self.yoff_fb;
var w = self.xl;
var h = self.yl;
if (is_enter) {
h += self.yl;
h += self.yd - self.yl;
}
var id = "fb" + x + y;
// DO NOT CHANGE COLOR NAME without fixing Android first
self.make_div(xx, yy, w, h, self.pointer_div,
id, "green");
self.overlays_timer = H.delay(function () {
self.remove_overlays();
}, 350);
};
Hp12c_keyboard.prototype.has_css3 = function (hook)
{
if (H.embedded) {
window.xlog("CSS3 x embedded engine");
return true;
} else if (H.disp_fb_offset_x === undefined) {
window.xlog("No feedback coordinates");
return false;
} else if (hook.style['zIndex'] === undefined ||
hook.style['borderRadius'] === undefined ||
hook.style['opacity'] === undefined ||
hook.style['pointerEvents'] === undefined) {
// we need these CSS2/CSS3 style elements
window.xlog("CSS3 property misssing");
return false;
}
window.xlog("CSS3 present");
return true;
};
Hp12c_keyboard.prototype.make_div = function (x, y, w, h, hook, id, color)
{
var self = this;
w = Math.min(x + w, self.pointer_div_width - 1) - x;
h = Math.min(y + h, self.pointer_div_height - 1) - y;
if (H.embedded) {
self.pointer_div.makeDiv(x, y, w, h, self.highlight_radius, color);
return;
}
var div = H.createElem('div');
div.id = id;
div.style.width = "" + w + "px";
div.style.height = "" + h + "px";
div.style.backgroundColor = color;
div.style.position = "absolute";
div.style.left = "" + x + "px";
div.style.top = "" + y + "px";
div.style.zIndex = 2;
div.style.opacity = 0.3;
div.style.borderRadius = self.highlight_radius;
div.style.pointerEvents = "none";
hook.appendChild(div);
self.overlays.push(div);
// window.xlog("" + x + " " + y + " " + w + " " + h);
};
Hp12c_keyboard.prototype.reset_overlays_timer = function ()
{
var self = this;
if (self.overlays_timer !== null) {
H.cancel_delay(self.overlays_timer);
self.overlays_timer = null;
}
};
Hp12c_keyboard.prototype.remove_overlays = function ()
{
var self = this;
self.overlays_timer = null;
if (H.embedded) {
self.pointer_div.clearDiv();
return;
}
while (self.overlays.length > 0) {
var div = self.overlays.shift();
div.parentNode.removeChild(div);
}
};
/*jslint white: true, undef: true, nomen: true, regexp: true, strict: true, browser: true, sub: true, bitwise: true */
/*jshint globalstrict: true*/
/*global H */
"use strict";
H.hp1xc_keyboard_flavor = function (kbdtable)
{
kbdtable['w'] = 49;
kbdtable['W'] = 49;
kbdtable['y'] = 34;
kbdtable['Y'] = 34;
kbdtable['h'] = 16;
kbdtable['H'] = 16;
kbdtable['c'] = 35;
kbdtable['C'] = 35;
kbdtable['n'] = 11;
kbdtable['N'] = 11;
kbdtable['i'] = 12;
kbdtable['I'] = 12;
kbdtable['p'] = 13;
kbdtable['P'] = 13;
kbdtable['m'] = 14;
kbdtable['M'] = 14;
kbdtable['v'] = 15;
kbdtable['V'] = 15;
kbdtable['#'] = 23;
kbdtable['$'] = 24;
kbdtable['%'] = 25;
kbdtable['!'] = 21;
kbdtable['\\'] = 22;
kbdtable['d'] = 33;
kbdtable['D'] = 33;
kbdtable[String.fromCharCode(40)] = 33;
kbdtable['['] = 31;
kbdtable[']'] = 32;
kbdtable['?'] = 99;
kbdtable[String.fromCharCode(8)] = 98;
kbdtable['Z'] = 98;
kbdtable['z'] = 98;
kbdtable['e'] = 26;
kbdtable['E'] = 26;
};
H.hp1xc_vertical_keyboard_flavor = function (vmap)
{
};
/*jslint white: true, undef: true, nomen: true, regexp: true, bitwise: true, strict: true, browser: true */
/*jshint globalstrict: true*/
/*global H */
"use strict";
// test with 12C and 11C
function Hp12c_machine()
{
var self = this;
// algebraic operations
self.nvname = H.type_cookie;
// TODO this should be in init_memory()
// and unit tests should wait it to go back to 1
self.sti_level = 0;
// changed by unit tests only
self.rapid_default = 0;
self.init_memory();
}
/* Can be called before display and other components are still uninitialized */
Hp12c_machine.prototype.init_memory = function (n)
{
var self = this;
// calculator non-volatile memory -----------------------------------------------------------
self.x = 0;
self.y = 0;
self.z = 0;
self.w = 0;
self.last_x = 0;
// 15C imaginary parts of each register
self.xi = 0;
self.yi = 0;
self.zi = 0;
self.wi = 0;
self.last_xi = 0;
self.mA = [];
self.mB = [];
self.mC = [];
self.mD = [];
self.mE = [];
self.msA = [0, 0];
self.msB = [0, 0];
self.msC = [0, 0];
self.msD = [0, 0];
self.msE = [0, 0];
self.mR = 20; // A=20, B=21 ...
// 16C "high" parts of 64-bit integer numbers
// 15C also use these flags as matrix pointers
self.xh = 0;
self.yh = 0;
self.zh = 0;
self.wh = 0;
self.last_xh = 0;
// 15C matrixes never go to STO memories
self.stomemoryh = [];
self.wordsize = H.DEFAULT_WORDSIZE;
self.intwindow = 0;
self.negative_repr = 2;
self.stomemory = [];
self.finmemory = [];
self.njmemory = [];
self.index = 0; // not-12C
self.indexh = 0; // 15C
self.ram = [];
self.program_size = 1; // for STOP in [0]
self.flags = [];
var i;
for (i = 0; i < H.FLAGS_MAX; ++i) {
self.flags[i] = 0;
}
self.decimals = 2;
self.comma = 0;
self.altdisplay = 1; // 16c alternative (apocryphal) displays
self.begin = 0;
self.dmy = 0;
self.compoundf = 0;
self.notation = H.NOTATION_FIX;
if (H.type === "16c") {
self.notation = H.NOTATION_INT_HEX;
}
self.trigo = H.TRIGO_DEG;
self.complex = 0;
self.user = 0;
self.prng = 0;
// 15C thing to handle solve, integration
self.running_context = [];
self.osolve = null;
self.ointegrate = null;
// volatile memory ---------------------------------------------------------------------
self.UNDOABLE_NONE = 0;
self.UNDOABLE_CLX = 1;
self.UNDOABLE_BSP = 2;
self.UNDOABLE_BSP_TYPING = 3;
self.UNDOABLE_CLEAR_REG = 4;
self.UNDOABLE_CLEAR_STAT = 5;
self.UNDOABLE_CLEAR_FIN = 6;
self.algmode = 0;
self.algebra = [];
self.undoable = 0; // UNDOABLE_* values
self.undoable_assets = null;
self.program_mode = 0;
self.ip = 0;
self.pushed = 0;
self.pushed_cplx_exception = 0;
self.gtoxx = "";
self.modifier = 0;
self.do_fincalc = 0;
self.xmode = -1;
self.typed_mantissa = "";
self.typed_decimals = "";
self.typed_mantissa_signal = 1;
self.typed_exponent = "00";
self.typed_exponent_signal = 1;
self.modal_state = H.MODAL_NONE;
self.modal_observers = {};
self.modal_data = null;
self.call_stack = []; // not-12C
// Visual feedback
self.fb = 1;
// "Rapid" programming and financial - does not try to imitate HP1xC speed
self.rapid = self.rapid_default;
if (H.type === '11c') {
self.nvN = ['x', 'y', 'z', 'w', 'last_x',
'decimals', 'comma', 'index', 'prng',
'trigo', 'user', 'notation', 'fb', 'rapid'];
self.nvAN = ['stomemory', 'flags'];
} else if (H.type === '10c') {
self.nvN = ['x', 'y', 'z', 'w', 'last_x',
'decimals', 'comma', 'prng',
'trigo', 'notation', 'fb', 'rapid'];
self.nvAN = ['stomemory'];
} else if (H.type === '15c') {
self.nvN = ['x', 'y', 'z', 'w', 'last_x',
'xi', 'yi', 'zi', 'wi', 'last_xi',
'xh', 'yh', 'zh', 'wh', 'last_xh',
'decimals', 'comma', 'index', 'indexh', 'prng',
'trigo', 'user', 'notation', 'complex',
'mR', 'fb', 'rapid'];
self.nvAN = ['stomemory', 'flags',
'mA', 'mB', 'mC', 'mD', 'mE',
'msA', 'msB', 'msC', 'msD', 'msE'];
} else if (H.type === '16c') {
self.nvN = ['x', 'y', 'z', 'w', 'last_x',
'xh', 'yh', 'zh', 'wh', 'last_xh', 'prng',
'decimals', 'comma', 'index', 'notation',
'wordsize', 'intwindow', 'negative_repr',
'fb', 'rapid'];
self.nvAN = ['stomemory', 'stomemoryh', 'flags'];
} else {
// 12C
self.nvN = ['x', 'y', 'z', 'w', 'last_x', 'algmode',
'decimals', 'comma', 'begin', 'prng',
'dmy', 'compoundf', 'notation', 'fb',
'rapid'];
self.nvAN = ['stomemory', 'finmemory', 'njmemory'];
}
self.nvAX = ['ram'];
};
Hp12c_machine.prototype.sto_Reset = function (i)
{
var self = this;
self.stomemory[i] = 0;
self.stomemoryh[i] = 0;
};
Hp12c_machine.prototype.reg_Reset = function (n)
{
var self = this;
self[n] = 0;
self[n + "h"] = 0;
self[n + "i"] = 0;
};
Hp12c_machine.prototype.sto_Swap_reg = function (i, n)
{
var self = this;
var tr = {r: self.stomemory[i], h: self.stomemoryh[i]};
var ts = {r: self[n], h: self[n + "h"]};
if (self.notation >= H.NOTATION_INT) {
// yes, this is right
// this has also the side effect of casting to int
self.cast_wordsize(tr);
self.cast_wordsize(ts);
}
self.stomemory[i] = ts.r;
if (H.type === "16c") {
self.stomemoryh[i] = ts.h;
} else {
self.stomemoryh[i] = 0;
}
self[n] = tr.r;
self[n + "h"] = tr.h;
};
Hp12c_machine.prototype.sto_To_reg = function (i, n)
{
var self = this;
var t = {r: self.stomemory[i], h: self.stomemoryh[i]};
if (self.notation >= H.NOTATION_INT) {
// yes, this is right
// this has also the side effect of casting to int
self.cast_wordsize(t);
}
// STO does not have imaginary part
self[n] = t.r;
self[n + "h"] = t.h; // 16C integer
};
Hp12c_machine.prototype.reg_To_sto = function (n, i)
{
var self = this;
var t = {r: self[n], h: self[n + "h"]};
if (self.notation >= H.NOTATION_INT) {
// yes, this is right
// this has also the side effect of casting to int
self.cast_wordsize(t);
}
// imaginary part not considered
self.stomemory[i] = t.r;
if (H.type === "16c") {
// 15c matrixes don't go into STO
self.stomemoryh[i] = t.h;
} else {
self.stomemoryh[i] = 0;
}
};
Hp12c_machine.prototype.reg_To_reg = function (nf, nt)
{
var self = this;
var t = {r: self[nf], h: self[nf + "h"], i: self[nf + "i"]};
if (self.notation >= H.NOTATION_INT) {
// yes, this is right
// this has also the side effect of casting to int
self.cast_wordsize(t);
}
self[nt] = t.r;
self[nt + "h"] = t.h;
self[nt + "i"] = t.i;
};
Hp12c_machine.prototype.reg_tuple = function (n)
{
var self = this;
var t = {};
t.r = self[n];
t.i = self[n + "i"];
t.h = self[n + "h"];
if (self.notation >= H.NOTATION_INT) {
// yes, this is right
// this has also the side effect of casting to int
self.cast_wordsize(t);
}
return t;
};
Hp12c_machine.prototype.reg_real = function (n)
{
var self = this;
return self.reg_tuple(n).r;
};
Hp12c_machine.prototype.cast_wordsize = function (t)
{
var self = this;
H.cast_wordsize(t, self.wordsize);
};
Hp12c_machine.prototype.cast_wordsize_in_accumulators = function ()
{
var self = this;
var i;
var regs = ["x", "y", "z", "w", "last_x"];
for (i = 0; i < regs.length; ++i) {
// getter and setter cast to wordsize, so no need to
// do that explicitly
self.reg_Set_tuple(regs[i], self.reg_tuple(regs[i]));
}
// storage is not cast immediately. If the user goes back
// to bigger wordsize he should get the original values.
/*
for (i = 0; i < self.sto_mem_len(); ++i) {
self.sto_Set_tuple(i, self.sto_tuple(i));
}
*/
};
Hp12c_machine.prototype.reg_Set_tuple = function (n, t)
{
var self = this;
if (self.notation >= H.NOTATION_INT) {
// yes, this is right
self.cast_wordsize(t);
}
self[n] = t.r;
self[n + "i"] = t.i;
self[n + "h"] = t.h;
};
Hp12c_machine.prototype.reg_Set_real = function (n, v)
{
var self = this;
// check clients
return self.reg_Set_tuple(n, {r: v, i: 0, h: 0});
};
Hp12c_machine.prototype.reg_Set_real_only = function (n, v)
{
var self = this;
if (H.type === "15c" && self.is_complex_mode()) {
return self.reg_Set_tuple(n, {r: v, i: self.xi, h: 0});
}
return self.reg_Set_real(n, v);
};
Hp12c_machine.prototype.sto_tuple = function (i)
{
var self = this;
var t = {};
t.r = self.stomemory[i];
t.h = self.stomemoryh[i];
t.i = 0; // filler to make it compatible with reg tuple
if (self.notation >= H.NOTATION_INT) {
self.cast_wordsize(t);
}
return t;
};
Hp12c_machine.prototype.sto_Set_tuple = function (i, t)
{
var self = this;
if (self.notation >= H.NOTATION_INT) {
self.cast_wordsize(t);
}
self.stomemory[i] = t.r;
self.stomemoryh[i] = ((H.type === "16c") ? t.h : 0);
// t.i not used
};
Hp12c_machine.prototype.sto_mem_ref = function ()
{
var self = this;
// Used by floating-point functions only, so this is ok
return self.stomemory;
};
Hp12c_machine.prototype.sto_mem_len = function ()
{
var self = this;
return self.stomemory.length;
};
Hp12c_machine.prototype.program_limit = function ()
{
var self = this;
if (H.type === "11c" || H.type === "15c" || H.type === "16c") {
return Math.min(H.ram_MAX - 1, self.program_size - 1);
}
return H.ram_MAX - 1;
};
Hp12c_machine.prototype.ram_available = function ()
{
var self = this;
if (H.type === "11c" || H.type === "15c" || H.type === "16c") {
return Math.min(H.ram_MAX - self.program_size);
}
return H.ram_MAX - 1;
};
Hp12c_machine.prototype.incr_ip = function (delta)
{
var self = this;
// do not allow to go above program limit, but do not zero
// because if in RUNNING mode, pgrm module always increases IP.
// If we make ip=0, pgrm does ++ip and then we have an
// infinite loop.
self.ip = Math.max(0, Math.min(self.program_limit(), self.ip + delta));
};
/* Called when H.display is already in place */
Hp12c_machine.prototype.init = function ()
{
var self = this;
self.init_memory();
self.clear_prog(1);
self.do_clear_reg(); // implies reg, sto, fin
self.clear_stack();
self.display_flags(); // some flags affect display
};
Hp12c_machine.prototype.clear_fin = function ()
{
var self = this;
var e;
if (H.type === "12c-platinum") {
self.algebra = [];
self.display_parentheses();
self.undoable = self.UNDOABLE_CLEAR_FIN;
self.undoable_assets = [];
for (e = 0; e < 5; ++e) {
self.undoable_assets[e] = self.finmemory[e];
}
self.display_undo();
}
self.do_clear_fin();
};
Hp12c_machine.prototype.do_clear_fin = function ()
{
var self = this;
for (var e = 0; e < 5; ++e) {
self.finmemory[e] = 0;
}
self.display_result();
};
Hp12c_machine.prototype.clear_statistics = function ()
{
var self = this;
var e;
if (H.type === "12c-platinum") {
self.algebra = [];
self.display_parentheses();
self.undoable = self.UNDOABLE_CLEAR_STAT;
var d = {};
self.undoable_assets = d;
d.stack = {};
d.stack.x = self.reg_real("x");
d.stack.y = self.reg_real("y");
d.stack.z = self.reg_real("z");
d.stack.w = self.reg_real("w");
d.sto = [];
for (e = H.STAT_MIN; e <= H.STAT_MAX; ++e) {
d.sto[e] = self.sto_tuple(e);
}
self.display_undo();
}
// statistics share memory with STO memory
for (e = H.STAT_MIN; e <= H.STAT_MAX; ++e) {
self.sto_Reset(e);
}
self.reg_Reset("x");
self.reg_Reset("y");
self.reg_Reset("z");
self.reg_Reset("w");
self.display_result();
};
Hp12c_machine.prototype.clear_prog = function (in_pgrm)
{
var self = this;
if (H.type === "12c-platinum") {
self.algebra = [];
self.display_parentheses();
}
if (in_pgrm) {
self.ram[0] = "";
for (var e = 1; e < H.ram_MAX; ++e) {
self.ram[e] = H.STOP_INSTRUCTION;
}
self.program_size = 1; // for STOP in [0]
} else {
self.display_result_s(false, true);
}
self.ip = 0;
};
Hp12c_machine.prototype.clear_sto = function ()
{
var self = this;
for (var e = 0; e < H.MEM_MAX; ++e) {
self.sto_Reset(e);
self.njmemory[e] = 1; // position 0 is read-only and always returns 1.
}
};
Hp12c_machine.prototype.cli = function (motive)
{
var self = this;
self.sti_level--;
window.console.ut_snap("cli ", self.sti_level + " " + motive);
// this is cumulative i.e. two calls to cli(x) must be
// counterbalanced by two sti(x)'s
if (self.sti_level === 0) {
H.keyboard.disable();
}
};
Hp12c_machine.prototype.sti = function (motive)
{
var self = this;
self.sti_level++;
window.console.ut_snap("sti ", self.sti_level + " " + motive);
if (self.sti_level === 1) {
H.keyboard.enable();
}
};
Hp12c_machine.prototype.clear_typing = function ()
{
var self = this;
var positive_clearing = (self.xmode > -1);
self.xmode = -1;
self.typed_mantissa = "";
self.typed_decimals = "";
self.typed_mantissa_signal = 1;
self.typed_exponent = "00";
self.typed_exponent_signal = 1;
return positive_clearing;
};
Hp12c_machine.prototype.display_result = function ()
{
var self = this;
self.display_result_s(true, true);
};
Hp12c_machine.prototype.display_result_s = function (reset_window, enable_pushed)
{
var self = this;
if (H.type === "16c") {
if (reset_window) {
if (self.intwindow !== 0) {
self.intwindow = 0;
self.display_wordstatus();
}
}
}
if (self.clear_typing()) {
// if a number was being typed, any further typing
// must push (e.g. 12 PSE 34 should push 12 to y,
// and not let it be overwritten by 34)
enable_pushed = true;
}
if (enable_pushed) {
self.pushed = 0;
self.pushed_cplx_exception = 0;
}
var t = self.display_result_in();
if (H.type === "15c") {
if (t.r >= H.value_max || t.r <= -H.value_max) {
// make display blink
self.set_overflow(true);
}
}
};
Hp12c_machine.prototype.display_result_in = function ()
{
var self = this;
var t = self.reg_tuple("x");
var matrix = self.matrix_in_reg("x");
if (! matrix) {
H.display.displayNumber(t);
} else {
var size = self.matrix_size(matrix);
H.display.displayMatrix(matrix, size[0], size[1]);
}
return t;
};
Hp12c_machine.prototype.display_matrix = function (n, r, c)
{
var self = this;
self.pushed = 0;
self.pushed_cplx_exception = 0;
self.clear_typing();
H.display.displayMatrix(n, r, c);
};
Hp12c_machine.prototype.display_all = function ()
{
var self = this;
self.display_result_in();
self.display_modifier();
self.display_begin();
self.display_dmyc();
self.display_pgrm();
self.display_algmode();
self.display_trigo();
self.display_user();
self.display_flags();
self.display_wordstatus();
self.display_undo();
self.display_parentheses();
};
Hp12c_machine.prototype.pse = function ()
{
var self = this;
if (H.type === "12c-platinum") {
self.algebra = [];
self.display_parentheses();
}
// PSE pushes the stack
// (we can't count on reset_modal() for this because it may be
// executed in a program, and reset_modal() only pushes the stack
// in interactive mode)
self.display_result_s(false, false);
// PSE is somewhat special because it is modal but it also
// disables keyboard, and can be programmed
self.cli("pse");
self.enter_modal(H.MODAL_PAUSE);
H.delay(function () {
self.sti("pse");
self.reset_modal();
}, 1200);
};
Hp12c_machine.prototype.toggle_decimal_character = function ()
{
var self = this;
if (H.type === "15c") {
self.set_overflow(false);
}
self.comma = (self.comma + 1) % H.SEPARATORS;
self.display_result();
H.storage.save();
window.xlog("Storage saved");
};
Hp12c_machine.prototype.toggle_decimal_and_altdisplay = function ()
{
var self = this;
// toggles altdisplay and comma alternatively
if (self.altdisplay) {
self.altdisplay = 0;
self.display_result_s(false, false);
self.display_wordstatus();
H.storage.save();
} else {
self.altdisplay = 1;
self.display_wordstatus();
self.toggle_decimal_character();
}
};
Hp12c_machine.prototype.clear_stack = function ()
{
var self = this;
self.reg_Reset("x");
self.reg_Reset("y");
self.reg_Reset("z");
self.reg_Reset("w");
self.reg_Reset("last_x");
};
Hp12c_machine.prototype.clear_reg = function ()
{
var self = this;
if (H.type === "12c-platinum") {
self.algebra = [];
self.display_parentheses();
self.undoable = self.UNDOABLE_CLEAR_REG;
var d = {};
self.undoable_assets = d;
d.stack = {};
d.stack.x = self.reg_real("x");
d.stack.y = self.reg_real("y");
d.stack.z = self.reg_real("z");
d.stack.w = self.reg_real("w");
d.stack.last_x = self.reg_real("last_x");
d.sto = [];
d.nj = [];
for (var e = 0; e <= H.MEM_MAX; ++e) {
d.sto[e] = self.sto_tuple(e);
d.nj[e] = self.njmemory[e];
}
d.fin = [];
for (e = 0; e < 5; ++e) {
d.fin[e] = self.finmemory[e];
}
self.display_undo();
}
self.do_clear_reg();
};
Hp12c_machine.prototype.do_clear_reg = function ()
{
var self = this;
if (H.type !== "11c" && H.type !== "15c" && H.type !== "16c") {
self.clear_stack();
}
self.index = 0;
self.indexh = 0;
self.do_clear_fin();
self.clear_sto();
self.display_result_s(false, false);
};
// HP-12C Errors
// 0 = Division by zero, LN(negative) etc.
// 1 = STO + arith + memory position if memory position > 4
// 2 = statistics
// 3 = IRR
// 4 = Memory full (only happens in emulator when program typing reaches position 99+1)
// 5 = Composite interest
// 6 = CFj if j >= 30
// 7 = IRR
// 8 = Date
Hp12c_machine.prototype.display_pgrm = function ()
{
var self = this;
H.display.show_pgrm(self.program_mode == H.PROGRAMMING,
self.program_mode >= H.RUNNING,
self.ip);
};
Hp12c_machine.prototype.display_trigo = function ()
{
var self = this;
H.display.show_trigo(self.trigo);
};
Hp12c_machine.prototype.display_user = function ()
{
var self = this;
H.display.show_user(self.user);
};
Hp12c_machine.prototype.display_algmode = function ()
{
var self = this;
H.display.show_algmode(self.algmode);
};
Hp12c_machine.prototype.display_error = function (err)
{
var self = this;
if (H.type == "12c-platinum") {
self.algebra = [];
self.display_parentheses();
}
self.clear_typing();
self.modal_data = err;
self.enter_modal(H.MODAL_ERROR);
if (self.program_mode >= H.RUNNING) {
// errors stop programs
H.pgrm.stop(2);
}
};
Hp12c_machine.prototype.modal = function ()
{
var self = this;
return self.modal_state;
};
Hp12c_machine.prototype.is_error = function ()
{
var self = this;
return self.modal_state === H.MODAL_ERROR;
};
Hp12c_machine.prototype.error = function ()
{
var self = this;
return (self.modal_state === H.MODAL_ERROR) ? self.modal_data : 0;
};
Hp12c_machine.prototype.enter_modal = function (m)
{
var self = this;
self.modal_state = m;
window.xlog("modal " + m);
H.display.recycle();
};
Hp12c_machine.prototype.reset_modal = function ()
{
var self = this;
var was = self.modal_state;
self.modal_state = H.MODAL_NONE;
self.modal_data = null;
window.xlog("rst modal " + was);
if (self.program_mode == H.INTERACTIVE) {
self.display_result_s(false, false);
} else if (self.program_mode == H.PROGRAMMING) {
self.display_program_opcode();
} else {
H.display.recycle();
}
var observers = self.modal_observers;
self.modal_observers = {};
H.defer(function () {
for (var name in observers) {
observers[name]();
}
});
};
Hp12c_machine.prototype.modal_observer = function (name, cb)
{
var self = this;
self.modal_observers[name] = cb;
};
Hp12c_machine.prototype.modal_observer_remove = function (name)
{
var self = this;
self.modal_observers[name] = undefined;
delete self.modal_observers[name];
};
Hp12c_machine.prototype.display_modifier2 = function (m)
{
var self = this;
H.display.show_modifier(m);
};
Hp12c_machine.prototype.display_modifier = function ()
{
var self = this;
self.display_modifier2(self.modifier);
};
Hp12c_machine.prototype.display_begin = function ()
{
var self = this;
H.display.show_begin(self.begin);
};
Hp12c_machine.prototype.display_carry = function ()
{
var self = this;
if (H.type === "16c") {
H.display.show_carry(self.flags[H.FLAG_CARRY]);
}
};
Hp12c_machine.prototype.display_overflow = function ()
{
var self = this;
if (H.type === "16c") {
H.display.show_overflow(self.flags[H.FLAG_OVERFLOW]);
} else if (H.type === "15c") {
H.display.set_blink(self.flags[H.FLAG_OVERFLOW]);
}
};
Hp12c_machine.prototype.display_complex = function ()
{
var self = this;
if (H.type === "15c") {
H.display.show_complex(self.flags[H.FLAG_COMPLEX]);
}
};
Hp12c_machine.prototype.display_wordstatus = function ()
{
var self = this;
if (H.type === "16c") {
var st = "";
if (self.notation >= H.NOTATION_INT && self.altdisplay) {
st = "" + self.wordsize + ",";
if (self.negative_repr) {
st += self.negative_repr;
} else {
st += "u";
}
st += "
w=" + self.intwindow;
}
H.display.show_wordstatus(st);
}
};
Hp12c_machine.prototype.display_flags = function ()
{
var self = this;
self.display_carry();
self.display_overflow();
self.display_complex();
};
Hp12c_machine.prototype.display_undo = function ()
{
var self = this;
if (H.type === "12c-platinum") {
H.display.show_undo(self.undoable);
}
};
Hp12c_machine.prototype.display_parentheses = function ()
{
var self = this;
if (H.type === "12c-platinum") {
var txt = "";
if (self.algmode) {
if (self.count_open_parentheses() > 0) {
txt = "( )";
} else if (self.algebra.length > 0) {
txt = "..";
}
}
H.display.show_parentheses(txt);
}
};
Hp12c_machine.prototype.display_dmyc = function ()
{
var self = this;
H.display.show_dmyc(self.dmy, self.compoundf);
};
Hp12c_machine.prototype.set_dmy = function (v)
{
var self = this;
self.dmy = v;
self.display_dmyc();
self.display_result();
};
Hp12c_machine.prototype.set_trigo = function (v)
{
var self = this;
self.trigo = v;
self.display_trigo();
self.display_result_s(true, false);
};
Hp12c_machine.prototype.rpn_mode = function ()
{
var self = this;
self.algmode = 0;
self.algebra = [];
self.display_parentheses();
self.display_algmode();
self.display_result_s(true, false);
};
Hp12c_machine.prototype.toggle_compoundf = function ()
{
var self = this;
self.compoundf = self.compoundf ? 0 : 1;
self.display_dmyc();
self.display_result_s(true, false);
};
Hp12c_machine.prototype.toggle_user = function ()
{
var self = this;
self.user = self.user ? 0 : 1;
self.display_user();
if (self.program_mode == H.INTERACTIVE) {
self.display_result_s(true, false);
}
};
Hp12c_machine.prototype.set_begin = function (v)
{
var self = this;
self.begin = v;
self.display_begin();
self.display_result();
};
Hp12c_machine.prototype.set_modifier = function (v)
{
var self = this;
self.modifier = v;
if (v == H.GTO || v == H.GTO_MOVE) {
// clean gto nn buffer on edge
self.gto_buf_clear();
}
self.display_modifier();
};
Hp12c_machine.prototype.set_decimals = function (d, notation)
{
var self = this;
if (d > 9) {
self.display_error(H.ERROR_IMPROPER_N);
return;
}
var enable_push = false;
if (self.notation >= H.NOTATION_INT) {
// 16C case
self.prepare_for_float_mode();
self.enable_push = true;
}
self.notation = notation;
self.decimals = d;
self.display_wordstatus();
self.display_result_s(true, enable_push);
};
Hp12c_machine.prototype.set_decimals_exponential = function ()
{
var self = this;
if (self.notation >= H.NOTATION_INT) {
self.prepare_for_float_mode();
self.intwindow = 0;
}
self.notation = H.NOTATION_SCI;
self.decimals = 10;
self.display_wordstatus();
self.display_result();
};
Hp12c_machine.prototype.rst_modifier = function (df)
{
var self = this;
if (df) {
self.do_fincalc = 0; // disarms financial calculation
}
self.modifier = 0;
self.display_modifier();
};
Hp12c_machine.prototype.push = function ()
{
var self = this;
self.reg_To_reg("z", "w");
self.reg_To_reg("y", "z");
self.reg_To_reg("x", "y");
self.pushed = 1;
};
Hp12c_machine.prototype.digit_add_chk_int = function (digit, typed)
{
var self = this;
var digit_bits = H.digit_bits[self.notation];
var max_digits = Math.ceil(self.wordsize / digit_bits);
if (typed.length >= max_digits) {
// all allowable digits typed
digit = null;
}
if (digit !== null) {
digit = digit.toString(16);
}
return digit;
};
Hp12c_machine.prototype.chk_int_overflow = function (typed)
{
var self = this;
var digit_bits = H.digit_bits[self.notation];
var max_digits = self.wordsize / digit_bits;
var max_digits_c = Math.ceil(max_digits);
var max_digits_f = Math.floor(max_digits);
if ((typed.length >= max_digits_c) && (max_digits_c !== max_digits_f)) {
// test if MSB digit "splits" ie. has more bits than there
// are bits still allowed by the word size. In this case,
// MSB digit is cast to zero.
// A simple bit count is not ok because in radix=10 every bit
// depends on all digits, so it is not practical to detect overflow
// based on the fact that 1 decimal digit ~= 3.3 bits
var radix = H.radix[self.notation];
var x1 = H.string_to_integer_fast(typed, self.negative_repr,
self.wordsize, radix);
var x2 = H.string_to_integer_fast(typed, self.negative_repr,
self.wordsize + digit_bits,
radix);
if (x1.r !== x2.r || x1.h !== x2.h) {
typed = "0" + typed.substr(1);
}
}
return typed;
};
Hp12c_machine.prototype.digit_add = function (d)
{
var self = this;
var radix = H.radix[self.notation] || 10;
if (d >= radix) {
return;
}
if (H.type === "12c-platinum") {
if (self.undoable > self.UNDOABLE_NONE) {
self.undoable = self.UNDOABLE_NONE;
self.undoable_assets = null;
self.display_undo();
}
}
if (self.xmode == -1) {
if (self.notation >= H.NOTATION_INT) {
d = self.digit_add_chk_int(d, self.typed_mantissa);
}
if (d !== null) {
if (! self.pushed) {
self.push(); // push stack when result is immediately followed by typing
}
// just displayed a result
self.clear_typing();
if (self.notation >= H.NOTATION_INT) {
self.typed_mantissa = self.chk_int_overflow("" + d);
} else {
self.typed_mantissa += "" + d;
}
self.xmode = 0;
}
} else if (self.xmode === 0) {
if (self.notation >= H.NOTATION_INT) {
d = self.digit_add_chk_int(d, self.typed_mantissa);
if (d !== null) {
self.typed_mantissa = self.chk_int_overflow(self.typed_mantissa + "" + d);
}
} else {
if (self.typed_mantissa.length < H.display_len) {
self.typed_mantissa += "" + d;
}
}
} else if (self.xmode === 1) {
// integer mode never reaches this branch due to decimal_point_mode
if ((self.typed_mantissa.length + self.typed_decimals.length) < H.display_len) {
self.typed_decimals += "" + d;
}
} else if (self.xmode === 100) {
// integer mode never gets this branch
self.typed_exponent = self.typed_exponent.substr(1, 1);
self.typed_exponent += "" + d;
}
self.display_typing();
};
Hp12c_machine.prototype.display_typing_integer = function ()
{
var self = this;
var tu = H.string_to_integer_fast(self.typed_mantissa, self.negative_repr,
self.wordsize, H.radix[self.notation]);
self.reg_Set_tuple("x", tu);
H.display.displayTypedNumber_integer(self.reg_tuple("x"), self.xmode,
self.typed_mantissa.length);
};
Hp12c_machine.prototype.display_typing = function ()
{
var self = this;
self.pushed = 0;
if (H.type === "16c" && self.notation >= H.NOTATION_INT) {
self.display_typing_integer();
return;
}
var x = self.typed_mantissa_signal *
parseFloat(self.typed_mantissa + "." + self.typed_decimals + "0") *
Math.pow(10, parseInt("0" + self.typed_exponent, 10) * self.typed_exponent_signal);
if (self.pushed_cplx_exception) {
self.reg_Set_real_only("x", x);
} else {
self.reg_Set_real("x", x);
}
H.display.displayTypedNumber(self.typed_mantissa_signal, self.typed_mantissa,
self.typed_decimals, self.typed_exponent, self.typed_exponent_signal,
self.xmode, self.notation);
};
Hp12c_machine.prototype.digit_delete = function ()
{
var self = this;
var number_signal;
var i;
if (H.type === "15c") {
self.set_overflow(false);
}
if (self.xmode == -1) {
if (H.type === "12c-platinum") {
// Backspace equivalent to CLx for "undo" operation
self.undoable = self.UNDOABLE_CLX;
self.undoable_assets = self.reg_real("x");
self.display_undo();
}
var imaginary = 0;
if (self.is_complex_mode()) {
// preserve imaginary
imaginary = self.xi;
}
self.reg_Set_tuple("x", {r: 0, h: 0, i: imaginary});
// changes to in-place number editing
// (does not push again when new number is typed)
self.pushed = 1;
self.pushed_cplx_exception = 1;
H.display.displayNumber(self.reg_tuple("x"));
return;
}
if (H.type === "12c-platinum") {
self.undoable = self.UNDOABLE_BSP_TYPING;
var a = [];
self.undoable_assets = a;
a[0] = self.xmode;
a[1] = self.typed_mantissa;
a[2] = self.typed_decimals;
a[3] = self.typed_exponent;
a[4] = self.typed_mantissa_signal;
a[5] = self.typed_exponent_signal;
self.display_undo();
}
if (self.xmode === 0) {
i = self.typed_mantissa.length - 1;
if (i >= 0) {
self.typed_mantissa = self.typed_mantissa.substr(0, i);
}
} else if (self.xmode === 1) {
i = self.typed_decimals.length - 1;
if (i < 0) {
// decimal point mode but no decimal typed
self.xmode = 0;
} else {
self.typed_decimals = self.typed_decimals.substr(0, i);
}
} else if (self.xmode === 100) {
if (parseInt("0" + self.typed_exponent, 10) === 0) {
self.typed_exponent = "00";
self.typed_exponent_signal = 1;
if (self.typed_decimals.length > 0) {
self.xmode = 1;
} else {
self.xmode = 0;
}
} else {
self.typed_exponent = "0" + self.typed_exponent.substr(0, 1);
}
}
self.display_typing();
};
Hp12c_machine.prototype.input_exponential = function ()
{
var self = this;
if (self.notation >= H.NOTATION_INT) {
// no-op in 16C integer mode
return;
}
if (self.xmode == -1) {
if (! self.pushed) {
self.push(); // push stack when result is immediately followed by typing
}
self.clear_typing();
self.typed_mantissa = "1";
} else if (self.xmode != 100) {
if (self.typed_mantissa.length > (H.display_len - 3)) {
// too long; refuse
return;
}
if (parseInt("0" + self.typed_mantissa, 10) === 0) {
// no integer part
self.typed_mantissa = "0";
var val_dec = parseInt("0" + self.typed_decimals, 10);
if (val_dec === 0) {
// both integer and decimal parts all zero
self.typed_mantissa = "1";
} else {
// test for irreductible decimals like 0.000000001
var n_dec = val_dec.toFixed(0);
var zeros = self.typed_decimals.length - ("" + n_dec).length;
// if no decimal typed yet, zeros gets -1
zeros = Math.max(0, zeros);
if ((self.typed_mantissa.length + zeros) >=
(H.display_len - 3)) {
// too long; refuse
return;
}
}
}
}
self.xmode = 100;
self.display_typing();
};
Hp12c_machine.prototype.decimal_point_mode = function ()
{
var self = this;
if (self.notation >= H.NOTATION_INT) {
// no-op in 16C integer mode
return;
}
if (self.xmode == -1) {
// just displayed a result
if (! self.pushed) {
self.push(); // push stack when result is immediately followed by typing
}
self.clear_typing();
}
if (self.typed_mantissa.length <= 0) {
self.typed_mantissa = "0";
}
self.xmode = 1;
self.display_typing();
};
Hp12c_machine.prototype.chs_integer = function ()
{
var self = this;
// CHS always goes to result mode
self.save_lastx();
var xt = self.reg_tuple("x");
var calc = H.integer_inv([xt.h, xt.r], self.negative_repr, self.wordsize);
self.reg_Set_tuple("x", calc.result);
self.set_overflow(calc.overflow);
self.display_result();
};
Hp12c_machine.prototype.chs = function ()
{
var self = this;
if (self.matrix_in_reg("x")) {
self.matrix_chs();
return;
}
if (self.notation >= H.NOTATION_INT) {
self.chs_integer();
return;
}
if (self.xmode === -1) {
if (self.is_complex_mode()) {
self.reg_Set_real_only("x", -self.reg_real("x"));
} else {
self.reg_Set_real("x", -self.reg_real("x"));
}
self.display_result();
return;
}
if (self.xmode == 100) {
// input mode, inputting exponential
self.typed_exponent_signal *= -1;
} else {
self.typed_mantissa_signal *= -1;
}
self.display_typing();
};
Hp12c_machine.prototype.pop = function ()
{
var self = this;
self.reg_To_reg("y", "x");
self.reg_To_reg("z", "y");
self.reg_To_reg("w", "z");
};
Hp12c_machine.prototype.save_lastx = function ()
{
var self = this;
if (! self.algmode) {
self.reg_To_reg("x", "last_x");
}
};
Hp12c_machine.prototype.lstx = function ()
{
var self = this;
if (! self.pushed) {
self.push();
}
self.reg_To_reg("last_x", "x");
self.display_result();
};
Hp12c_machine.prototype.shv = function ()
{
var self = this;
if (H.type === "12c-platinum") {
self.algebra = [];
self.display_parentheses();
}
self.push();
if (self.notation >= H.NOTATION_INT) {
self.reg_Set_real("x", H.sve * 10);
} else {
self.reg_Set_real("x", H.sve);
}
self.display_result();
};
Hp12c_machine.prototype.test_offsets = function ()
{
var self = this;
H.keyboard.test();
};
Hp12c_machine.prototype.toggle_feedback = function ()
{
var self = this;
self.fb = self.fb ? 0 : 1;
window.xlog("Toggling feedback to " + self.fb);
};
Hp12c_machine.prototype.rapid_on = function ()
{
var self = this;
self.rapid = 1;
window.xlog("Toggling rapid ON");
};
Hp12c_machine.prototype.rapid_off = function ()
{
var self = this;
self.rapid = 0;
window.xlog("Toggling rapid OFF");
};
Hp12c_machine.prototype.apocryphal = function (i)
{
var self = this;
if (H.type === "12c-platinum") {
self.algebra = [];
self.display_parentheses();
}
// to be overridden as necessary; this is here just for testing
self.push();
self.reg_Set_real("x", 140 + i);
self.display_result();
};
Hp12c_machine.prototype.clear_prefix = function ()
{
var self = this;
if (self.notation >= H.NOTATION_INT) {
return;
}
if (H.type == "12c-platinum") {
self.algebra = [];
self.display_parentheses();
}
var n = Math.abs(self.reg_real("x"));
var order = Math.log(n) / Math.log(10);
if (H.badnumber(order)) {
// tends to zero
order = 1;
}
// result may have 11 significant digits in corner cases
n = n * Math.pow(10, H.display_len - Math.ceil(order));
var s = n.toFixed(0);
s = H.zeropad(s, H.display_len); // probably unnecessary
s = s.substr(0, 10);
H.display.show_nopgrm(" " + s);
if (self.program_mode < H.RUNNING) {
self.enter_modal(H.MODAL_PRESS);
} else {
// can only happen in unit tests
}
};
Hp12c_machine.prototype.x_exchange_y = function ()
{
var self = this;
var tmp = self.reg_tuple("x");
self.reg_To_reg("y", "x");
self.reg_Set_tuple("y", tmp);
self.display_result();
};
Hp12c_machine.prototype.fix_index = function ()
{
var self = this;
self.indexh = 0;
var index = Math.floor(Math.abs(self.index));
if (index >= H.MEM_MAX) {
self.display_error(H.ERROR_INDEX);
return null;
}
return index;
};
Hp12c_machine.prototype.x_exchange_index = function ()
{
var self = this;
if (self.matrix_in_index()) {
self.x_exchange_matrix_index();
return;
}
var index = self.fix_index();
if (index === null) {
return;
}
self.sto_Swap_reg(index, "x");
self.display_result();
};
Hp12c_machine.prototype.x_exchange_for = function (mem_position)
{
var self = this;
self.sto_Swap_reg(mem_position, "x");
self.display_result();
};
Hp12c_machine.prototype.x_exchange_index_itself = function ()
{
var self = this;
// (reg_Set_real calls reg_Set_tuple which casts an eventual
// float index to integer.)
var tmp = self.reg_tuple("x");
self.reg_Set_tuple("x", {r: self.index, h: self.indexh, i: 0});
self.index = tmp.r;
self.indexh = tmp.h;
self.display_result();
};
Hp12c_machine.prototype.mem_info = function ()
{
var self = this;
var mem = self.ram_available();
var stolen = self.sto_mem_len();
--stolen;
var stolen_txt = (stolen % 100).toFixed(0);
H.display.show_nopgrm("P-" + H.zeropad(mem, H.ram_ADDR_SIZE) + " R-" + stolen_txt, false);
self.enter_modal(H.MODAL_PRESS);
};
Hp12c_machine.prototype.sf = function (i)
{
var self = this;
if (i >= self.flags.length) {
self.display_error(H.type === "16c" ? H.ERROR_FLAG16 : H.ERROR_FLAG);
return;
}
self.do_sf(i);
self.display_result();
};
Hp12c_machine.prototype.do_sf = function (i)
{
var self = this;
self.flags[i] = 1;
self.display_flags();
};
Hp12c_machine.prototype.cf = function (i)
{
var self = this;
if (i >= self.flags.length) {
self.display_error(H.type === "16c" ? H.ERROR_FLAG16 : H.ERROR_FLAG);
return;
}
self.do_cf(i);
self.display_result();
};
Hp12c_machine.prototype.do_cf = function (i)
{
var self = this;
self.flags[i] = 0;
if (H.type === "15c") {
if (i === H.FLAG_COMPLEX) {
self.xi = self.yi = self.zi = self.wi = self.last_xi = 0;
}
}
self.display_flags();
};
Hp12c_machine.prototype.f_question = function (i)
{
var self = this;
if (i >= self.flags.length) {
self.display_error(H.type === "16c" ? H.ERROR_FLAG16 : H.ERROR_FLAG);
return;
}
self.incr_ip(self.flags[i] ? 0 : 1);
};
Hp12c_machine.prototype.dissect_word = function (word)
{
var self = this;
var sgn = H.binary_sgn(word);
var index = H.cl5_round(Math.abs(word), 5);
var counter = Math.floor(index) * sgn;
index -= sgn * counter;
index *= 1000;
var cmp = Math.floor(index + 0.001);
index = Math.max(0, index - cmp);
index *= 100;
var incr = Math.floor(index + 0.1);
return [counter, cmp, incr];
};
Hp12c_machine.prototype.update_word = function (counter, cmp, incr)
{
var self = this;
var sgn = H.binary_sgn(counter);
counter = Math.abs(counter);
return sgn * (counter + cmp / 1000 + incr / 100000);
};
Hp12c_machine.prototype.isg_core = function (word)
{
var self = this;
var res = self.dissect_word(word);
var counter = res[0], cmp = res[1], incr = res[2];
counter += (incr === 0 ? 1 : incr);
self.incr_ip(counter > cmp ? 1 : 0);
return self.update_word(counter, cmp, incr);
};
Hp12c_machine.prototype.f_isg = function ()
{
var self = this;
var word = self.isg_core(self.index);
self.index = word;
self.indexh = 0;
};
Hp12c_machine.prototype.dse_core = function (word)
{
var self = this;
var res = self.dissect_word(word);
var counter = res[0], cmp = res[1], incr = res[2];
counter -= (incr === 0 ? 1 : incr);
// note that cmp >= 0; a negative counter means this is always True
self.incr_ip(counter <= cmp ? 1 : 0);
return self.update_word(counter, cmp, incr);
};
Hp12c_machine.prototype.f_dse = function ()
{
var self = this;
var word = self.dse_core(self.index);
self.index = word;
self.indexh = 0;
};
Hp12c_machine.prototype.r_down = function ()
{
var self = this;
var tmp = self.reg_tuple("x");
self.reg_To_reg("y", "x");
self.reg_To_reg("z", "y");
self.reg_To_reg("w", "z");
self.reg_Set_tuple("w", tmp);
self.display_result();
};
Hp12c_machine.prototype.r_up = function ()
{
var self = this;
var tmp = self.reg_tuple("x");
self.reg_To_reg("w", "x");
self.reg_To_reg("z", "w");
self.reg_To_reg("y", "z");
self.reg_Set_tuple("y", tmp);
self.display_result();
};
Hp12c_machine.prototype.clx = function ()
{
var self = this;
if (H.type === "12c-platinum") {
if (self.undoable > self.UNDOABLE_NONE) {
// CLx in this situation wipes undo possibility
self.undoable = self.UNDOABLE_NONE;
self.undoable_assets = null;
} else {
self.undoable = self.UNDOABLE_CLX;
self.undoable_assets = self.reg_real("x");
}
self.display_undo();
}
if (self.is_complex_mode()) {
self.reg_Set_real_only("x", 0);
} else {
self.reg_Reset("x");
}
self.display_result();
self.pushed = 1; // do not push if user retries typing
// replaced even by RCL
self.pushed_cplx_exception = 1;
};
Hp12c_machine.prototype.finish_arithmetic = function (res, a, b)
{
var self = this;
if (H.type === "16c") {
var over = Math.abs(res) > H.value_max;
self.set_overflow(over);
}
self.save_lastx();
self.pop();
self.reg_Set_real("x", H.arithmetic_round(res, a, b));
self.display_result();
};
Hp12c_machine.prototype.finish_arithmetic_complex = function (res, a, b)
{
var self = this;
self.save_lastx();
self.pop();
var tuple = {"r": H.arithmetic_round(res.r, a.r, b.r),
"i": H.arithmetic_round(res.i, a.i, b.i),
"h": 0};
self.reg_Set_tuple("x", tuple);
self.display_result();
};
Hp12c_machine.prototype.finish_arithmetic_int = function (calc)
{
var self = this;
self.save_lastx();
self.pop();
self.set_carry(calc.carry);
self.set_overflow(calc.overflow);
self.reg_Set_tuple("x", calc.result);
self.display_result();
};
Hp12c_machine.prototype.enter = function (g_modifier)
{
var self = this;
if (self.algmode) {
if (self.algebra.length > 0) {
// pending op, do not push
self.alg_resolve(1);
} else if (! g_modifier) {
self.push();
self.display_result();
self.pushed = 1;
} else {
// =, but nothing to solve, do not push
self.display_result();
}
} else {
self.easter_egg();
self.push();
self.display_result();
self.pushed = 1; // already pushed, do not push twice when user types new number
}
};
Hp12c_machine.prototype.easter_egg = function ()
{
var self = this;
if (self.x === 0xf457123) {
self.rapid_on();
} else if (self.x == 0xf457122) {
self.rapid_off();
}
};
Hp12c_machine.prototype.plus = function ()
{
var self = this;
if (self.matrix_in_reg("x") || self.matrix_in_reg("y")) {
self.matrix_plus();
return;
}
var x, y, calc;
if (self.notation >= H.NOTATION_INT) {
x = self.reg_tuple("x");
y = self.reg_tuple("y");
calc = H.integer_plus([x.h, x.r], [y.h, y.r],
self.negative_repr, self.wordsize);
self.finish_arithmetic_int(calc);
} else if (self.algmode) {
if (! self.alg_resolve(0)) {
return;
}
if (! self.algebra_rightmost_is_number()) {
self.algebra.push(self.reg_real("x"));
}
self.algebra.push("+");
window.xlog("[+] " + self.algebra.join(" "));
self.display_parentheses();
self.push();
self.display_result();
} else if (self.is_complex_mode()) {
x = self.reg_tuple("x");
y = self.reg_tuple("y");
calc = H.complex_plus(x, y);
self.finish_arithmetic_complex(calc, x, y);
} else {
x = self.reg_real("x");
y = self.reg_real("y");
self.finish_arithmetic(y + x, x, y);
}
};
Hp12c_machine.prototype.minus = function ()
{
var self = this;
if (self.matrix_in_reg("x") || self.matrix_in_reg("y")) {
self.matrix_minus();
return;
}
var x, y, calc;
if (self.notation >= H.NOTATION_INT) {
x = self.reg_tuple("x");
y = self.reg_tuple("y");
calc = H.integer_minus([y.h, y.r], [x.h, x.r],
self.negative_repr, self.wordsize);
self.finish_arithmetic_int(calc);
return;
} else if (self.algmode) {
if (! self.alg_resolve(0)) {
return;
}
if (! self.algebra_rightmost_is_number()) {
self.algebra.push(self.reg_real("x"));
}
self.algebra.push("-");
window.xlog("[-] " + self.algebra.join(" "));
self.display_parentheses();
self.push();
self.display_result();
} else if (self.is_complex_mode()) {
x = self.reg_tuple("x");
y = self.reg_tuple("y");
calc = H.complex_minus(y, x);
self.finish_arithmetic_complex(calc, x, y);
} else {
x = self.reg_real("x");
y = self.reg_real("y");
self.finish_arithmetic(y - x, x, y);
}
};
Hp12c_machine.prototype.multiply = function ()
{
var self = this;
if (self.matrix_in_reg("x") || self.matrix_in_reg("y")) {
self.matrix_multiply();
return;
}
var x, y, calc;
if (self.notation >= H.NOTATION_INT) {
x = self.reg_tuple("x");
y = self.reg_tuple("y");
calc = H.integer_multiply([x.h, x.r], [y.h, y.r],
self.negative_repr, self.wordsize);
// make sure multiplication does not change carry
calc.carry = self.get_carry();
self.finish_arithmetic_int(calc);
return;
} else if (self.algmode) {
if (! self.alg_resolve(0)) {
return;
}
if (! self.algebra_rightmost_is_number()) {
self.algebra.push(self.reg_real("x"));
}
self.algebra.push("*");
window.xlog("[*] " + self.algebra.join(" "));
self.display_parentheses();
self.push();
self.display_result();
} else if (self.is_complex_mode()) {
x = self.reg_tuple("x");
y = self.reg_tuple("y");
calc = H.complex_multiply(x, y);
self.finish_arithmetic_complex(calc, {r: 0, i: 0}, {r: 0, i: 0});
} else {
x = self.reg_real("x");
y = self.reg_real("y");
self.finish_arithmetic(y * x, 0, 0);
}
};
Hp12c_machine.prototype.divide = function ()
{
var self = this;
if (self.matrix_in_reg("x") || self.matrix_in_reg("y")) {
self.matrix_divide();
return;
}
var x, y, calc;
if (self.notation >= H.NOTATION_INT) {
x = self.reg_tuple("x");
y = self.reg_tuple("y");
calc = H.integer_divide([y.h, y.r], [x.h, x.r],
self.negative_repr, self.wordsize,
false);
if (calc.overflow) {
self.display_error(H.ERROR_DIVZERO);
} else {
calc.result = calc.result[0];
self.finish_arithmetic_int(calc);
}
return;
} else if (self.algmode) {
if (! self.alg_resolve(0)) {
return;
}
if (! self.algebra_rightmost_is_number()) {
self.algebra.push(self.reg_real("x"));
}
self.algebra.push("/");
window.xlog("[/] " + self.algebra.join(" "));
self.display_parentheses();
self.push();
self.display_result();
} else if (self.is_complex_mode()) {
x = self.reg_tuple("x");
y = self.reg_tuple("y");
calc = H.complex_divide(y, x);
if (calc.err) {
self.display_error(H.ERROR_DIVZERO);
} else {
self.finish_arithmetic_complex(calc, {r: 0, i: 0}, {r: 0, i: 0});
}
} else {
calc = self.reg_real("y") / self.reg_real("x");
if (H.badnumber(calc)) {
self.display_error(H.ERROR_DIVZERO);
} else {
self.finish_arithmetic(calc, 0, 0);
}
}
};
Hp12c_machine.prototype.poweryx = function ()
{
var self = this;
if (self.matrix_in_reg("x") || self.matrix_in_reg("y")) {
self.display_error(H.ERROR_MATRIX_OP);
return;
}
if (self.algmode) {
if (! self.alg_resolve(0)) {
return;
}
if (! self.algebra_rightmost_is_number()) {
self.algebra.push(self.reg_real("x"));
}
self.algebra.push("^");
window.xlog("[^] " + self.algebra.join(" "));
self.display_parentheses();
self.push();
self.display_result();
} else if (self.is_complex_mode()) {
var x = self.reg_tuple("x");
var y = self.reg_tuple("y");
var calc = H.complex_power(y, x);
if (calc.err) {
window.xlog("complex power err");
self.display_error(H.ERROR_DIVZERO);
} else {
self.finish_arithmetic_complex(calc, {r: 0, i: 0}, {r: 0, i: 0});
}
} else {
var yy = self.reg_real("y");
var xx = self.reg_real("x");
var res = Math.pow(yy, xx);
if (xx === 0 && yy === 0) {
res = NaN;
}
if (H.badnumber(res)) {
self.display_error(H.ERROR_DIVZERO);
} else {
self.finish_arithmetic(res, 0, 0);
}
}
};
Hp12c_machine.prototype.power10 = function ()
{
var self = this;
if (self.matrix_in_reg("x")) {
self.display_error(H.ERROR_MATRIX_OP);
return;
}
if (self.is_complex_mode()) {
var cres = H.complex_power10(self.reg_tuple("x"));
self.save_lastx();
self.reg_Set_tuple("x", cres);
self.display_result();
return;
}
// can be big but not NaN
var res = H.clamp(Math.pow(10.0, self.reg_real("x")));
self.save_lastx();
self.reg_Set_real("x", res);
self.display_result();
};
Hp12c_machine.prototype.reciprocal = function ()
{
var self = this;
if (self.matrix_in_reg("x")) {
self.matrix_reciprocal();
return;
}
if (self.is_complex_mode()) {
var cres = H.complex_reciprocal(self.reg_tuple("x"));
if (cres.err) {
self.display_error(H.ERROR_DIVZERO);
return;
}
self.save_lastx();
self.reg_Set_tuple("x", cres);
self.display_result();
return;
}
if (self.notation >= H.NOTATION_INT) {
// no-op in 16C integer mode
return;
}
var res = 1 / self.reg_real("x");
if (H.badnumber(res)) {
self.display_error(H.ERROR_DIVZERO);
} else {
self.save_lastx();
self.reg_Set_real("x", res);
self.display_result();
}
};
Hp12c_machine.prototype.square = function ()
{
var self = this;
if (self.matrix_in_reg("x")) {
self.display_error(H.ERROR_MATRIX_OP);
return;
}
if (self.is_complex_mode()) {
var cres = H.complex_square(self.reg_tuple("x"));
self.save_lastx();
self.reg_Set_tuple("x", cres);
self.display_result();
return;
}
// can overflow but is never NaN
var res = H.clamp(Math.pow(self.reg_real("x"), 2));
self.save_lastx();
self.reg_Set_real("x", res);
self.display_result();
};
Hp12c_machine.prototype.sqroot = function ()
{
var self = this;
if (self.matrix_in_reg("x")) {
self.display_error(H.ERROR_MATRIX_OP);
return;
}
if (self.is_complex_mode()) {
var cres = H.complex_sqrt(self.reg_tuple("x"));
self.save_lastx();
self.reg_Set_tuple("x", cres);
self.display_result();
return;
}
if (self.notation >= H.NOTATION_INT) {
var xt = self.reg_tuple("x");
var calc = H.integer_sqrt([xt.h, xt.r],
self.negative_repr,
self.wordsize);
if (calc.overflow) {
self.display_error(H.ERROR_DIVZERO);
} else {
self.save_lastx();
self.reg_Set_tuple("x", calc.result);
self.set_carry(calc.carry);
self.display_result();
}
return;
}
var res = Math.sqrt(self.reg_real("x"));
if (H.badnumber(res)) {
self.display_error(H.ERROR_DIVZERO);
} else {
self.save_lastx();
self.reg_Set_real("x", res);
self.display_result();
}
};
Hp12c_machine.prototype.exp = function ()
{
var self = this;
if (self.matrix_in_reg("x")) {
self.display_error(H.ERROR_MATRIX_OP);
return;
}
if (self.is_complex_mode()) {
// can't fail
var cres = H.complex_exp(self.reg_tuple("x"));
self.save_lastx();
self.reg_Set_tuple("x", cres);
self.display_result();
return;
}
// can't be NaN
var res = H.clamp(Math.exp(self.reg_real("x")));
self.save_lastx();
self.reg_Set_real("x", res);
self.display_result();
};
Hp12c_machine.prototype.ln_imag = function ()
{
var self = this;
return self.do_ln(true);
};
Hp12c_machine.prototype.ln = function ()
{
var self = this;
return self.do_ln(false);
};
Hp12c_machine.prototype.do_ln = function (bs_cplx)
{
var self = this;
if (self.matrix_in_reg("x")) {
self.display_error(H.ERROR_MATRIX_OP);
return;
}
if (self.is_complex_mode()) {
var cres = H.complex_ln(self.reg_tuple("x"));
if (cres.err) {
self.display_error(H.ERROR_DIVZERO);
return;
}
self.save_lastx();
self.reg_Set_tuple("x", cres);
self.display_result();
return;
} else if (bs_cplx) {
var tuple = {r: self.reg_real("x"), i: self.reg_real("y")};
var cres2 = H.complex_ln(tuple);
if (cres2.err) {
self.display_error(H.ERROR_DIVZERO);
return;
}
self.save_lastx();
self.reg_Set_real("x", cres2.r);
self.reg_Set_real("y", cres2.i);
self.display_result();
return;
}
var res = Math.log(self.reg_real("x"));
if (H.badnumber(res)) {
self.display_error(H.ERROR_DIVZERO);
} else {
self.save_lastx();
self.reg_Set_real("x", res);
self.display_result();
}
};
Hp12c_machine.prototype.log10 = function ()
{
var self = this;
if (self.matrix_in_reg("x")) {
self.display_error(H.ERROR_MATRIX_OP);
return;
}
if (self.is_complex_mode()) {
var cres = H.complex_log10(self.reg_tuple("x"));
if (cres.err) {
self.display_error(H.ERROR_DIVZERO);
return;
}
self.save_lastx();
self.reg_Set_tuple("x", cres);
self.display_result();
return;
}
var res = Math.log(self.reg_real("x")) / Math.log(10);
if (H.badnumber(res)) {
self.display_error(H.ERROR_DIVZERO);
} else {
self.save_lastx();
self.reg_Set_real("x", res);
self.display_result();
}
};
Hp12c_machine.prototype.trig = function (f)
{
var self = this;
if (self.matrix_in_reg("x")) {
self.display_error(H.ERROR_MATRIX_OP);
return;
}
if (self.is_complex_mode()) {
var name = "complex_" + f;
var cres = H[name](self.reg_tuple("x"));
if (cres.err) {
// only tan can yield error, due to our implementation
self.display_error(H.ERROR_DIVZERO);
return;
}
self.save_lastx();
self.reg_Set_tuple("x", cres);
self.display_result();
return;
}
var res = H[f](H.radians(self.reg_real("x"), self.trigo));
// sin, cos, tan can't yield NaN
res = H.clamp(res);
self.save_lastx();
self.reg_Set_real("x", res);
self.display_result();
};
Hp12c_machine.prototype.triginv = function (f)
{
var self = this;
if (self.matrix_in_reg("x")) {
self.display_error(H.ERROR_MATRIX_OP);
return;
}
if (self.is_complex_mode()) {
var name = "complex_" + f;
var cres = H[name](self.reg_tuple("x"));
if (cres.err) {
self.display_error(H.ERROR_DIVZERO);
return;
}
self.save_lastx();
self.reg_Set_tuple("x", cres);
self.display_result();
return;
}
var res = Math[f](self.reg_real("x"));
if (H.badnumber(res)) {
self.display_error(H.ERROR_DIVZERO);
} else {
self.save_lastx();
self.reg_Set_real("x", H.to_angle_mode(res, self.trigo));
self.display_result();
}
};
Hp12c_machine.prototype.htrig = function (f)
{
var self = this;
if (self.matrix_in_reg("x")) {
self.display_error(H.ERROR_MATRIX_OP);
return;
}
if (self.is_complex_mode()) {
var name = "complex_" + f;
var cres = H[name](self.reg_tuple("x"));
if (cres.err) {
self.display_error(H.ERROR_DIVZERO);
return;
}
self.save_lastx();
self.reg_Set_tuple("x", cres);
self.display_result();
return;
}
// hyperbolic sin/cos/tan can't yield NaN
var res = H[f].call(null, self.reg_real("x"));
res = H.clamp(res);
self.save_lastx();
self.reg_Set_real("x", res);
self.display_result();
};
Hp12c_machine.prototype.htriginv = function (f)
{
var self = this;
if (self.matrix_in_reg("x")) {
self.display_error(H.ERROR_MATRIX_OP);
return;
}
if (self.is_complex_mode()) {
var name = "complex_" + f;
var cres = H[name](self.reg_tuple("x"));
if (cres.err) {
self.display_error(H.ERROR_DIVZERO);
return;
}
self.save_lastx();
self.reg_Set_tuple("x", cres);
self.display_result();
return;
}
var res = H[f].call(null, self.reg_real("x"));
if (H.badnumber(res)) {
self.display_error(H.ERROR_DIVZERO);
} else {
self.save_lastx();
self.reg_Set_real("x", res);
self.display_result();
}
};
Hp12c_machine.prototype.intg = function ()
{
var self = this;
if (self.matrix_in_reg("x")) {
self.display_error(H.ERROR_MATRIX_OP);
return;
}
self.save_lastx();
self.reg_Set_real("x", Math.floor(Math.abs(self.reg_real("x"))) *
H.binary_sgn(self.reg_real("x")));
self.display_result();
};
Hp12c_machine.prototype.abs_integer = function ()
{
var self = this;
// CHS always goes to result mode
var xt = self.reg_tuple("x");
var calc = H.integer_abs([xt.h, xt.r], self.negative_repr, self.wordsize);
self.save_lastx();
self.reg_Set_tuple("x", calc.result);
self.set_overflow(calc.overflow);
self.display_result();
};
Hp12c_machine.prototype.abs = function ()
{
var self = this;
if (self.matrix_in_reg("x")) {
self.display_error(H.ERROR_MATRIX_OP);
return;
}
if (self.is_complex_mode()) {
var cres = H.complex_abs(self.reg_tuple("x"));
self.save_lastx();
self.reg_Set_tuple("x", cres);
self.display_result();
return;
}
if (self.notation >= H.NOTATION_INT) {
self.abs_integer();
return;
}
self.save_lastx();
self.reg_Set_real("x", Math.abs(self.reg_real("x")));
self.display_result();
};
Hp12c_machine.prototype.to_radians = function ()
{
var self = this;
if (self.matrix_in_reg("x")) {
self.display_error(H.ERROR_MATRIX_OP);
return;
}
self.save_lastx();
self.reg_Set_real("x", H.degrees_to_radians(self.reg_real("x")));
self.display_result();
};
Hp12c_machine.prototype.to_degrees = function ()
{
var self = this;
if (self.matrix_in_reg("x")) {
self.display_error(H.ERROR_MATRIX_OP);
return;
}
self.save_lastx();
self.reg_Set_real("x", H.radians_to_degrees(self.reg_real("x")));
self.display_result();
};
Hp12c_machine.prototype.to_hms = function ()
{
var self = this;
if (self.matrix_in_reg("x")) {
self.display_error(H.ERROR_MATRIX_OP);
return;
}
self.save_lastx();
self.reg_Set_real("x", H.hour_to_hms(self.reg_real("x")));
self.display_result();
};
Hp12c_machine.prototype.to_hour = function ()
{
var self = this;
if (self.matrix_in_reg("x")) {
self.display_error(H.ERROR_MATRIX_OP);
return;
}
self.save_lastx();
self.reg_Set_real("x", H.hms_to_hour(self.reg_real("x")));
self.display_result();
};
Hp12c_machine.prototype.pi = function ()
{
var self = this;
if (! self.pushed) {
self.push();
}
self.reg_Set_real("x", Math.PI);
self.display_result();
};
Hp12c_machine.prototype.random = function ()
{
var self = this;
if (! self.pushed) {
self.push();
}
self.prng = H.prng_next(self.prng);
self.reg_Set_real("x", self.prng / 10000000000);
self.display_result();
};
Hp12c_machine.prototype.random_sto = function ()
{
var self = this;
self.prng = H.prng_seed(self.reg_real("x"));
self.reg_Set_real("x", self.prng / 10000000000);
self.display_result();
};
Hp12c_machine.prototype.random_rcl = function ()
{
var self = this;
if (! self.pushed) {
self.push();
}
self.reg_Set_real("x", self.prng / 10000000000);
self.display_result();
};
Hp12c_machine.prototype.rnd = function ()
{
var self = this;
if (self.matrix_in_reg("x")) {
self.display_error(H.ERROR_MATRIX_OP);
return;
}
self.save_lastx();
self.reg_Set_real("x", H.cl5_round(self.reg_real("x"), self.decimals));
self.display_result();
};
Hp12c_machine.prototype.polar = function ()
{
var self = this;
if (self.matrix_in_reg("x") || self.matrix_in_reg("y")) {
self.display_error(H.ERROR_MATRIX_OP);
return;
}
if (self.is_complex_mode()) {
var cres = H.complex_to_polar(self.reg_tuple("x"));
cres.i = H.to_angle_mode(cres.i, self.trigo);
self.save_lastx();
self.reg_Set_tuple("x", cres);
self.display_result();
return;
}
var res = H.polar(self.reg_real("x"), self.reg_real("y"));
// H.polar can't throw NaN
var r = H.clamp(res[0]);
var angle = res[1];
self.save_lastx();
self.reg_Set_real("x", r);
self.reg_Set_real("y", H.to_angle_mode(angle, self.trigo));
self.display_result();
};
Hp12c_machine.prototype.orthogonal = function ()
{
var self = this;
if (self.matrix_in_reg("x") || self.matrix_in_reg("y")) {
self.display_error(H.ERROR_MATRIX_OP);
return;
}
if (self.is_complex_mode()) {
var arg = self.reg_tuple("x");
arg.i = H.radians(arg.i, self.trigo);
var cres = H.complex_to_cartesian(arg);
self.save_lastx();
self.reg_Set_tuple("x", cres);
self.display_result();
return;
}
var r = self.reg_real("x");
var angle = H.radians(self.reg_real("y"), self.trigo);
var res = H.orthogonal(r, angle);
// H.orthogonal can't throw NaN
var x = H.clamp(res[0]);
var y = H.clamp(res[1]);
self.save_lastx();
self.reg_Set_real("x", x);
self.reg_Set_real("y", y);
self.display_result();
};
Hp12c_machine.prototype.fatorial = function ()
{
var self = this;
if (self.matrix_in_reg("x")) {
self.display_error(H.ERROR_MATRIX_OP);
return;
}
// 12C-BlackScholes can do gamma as well
if (H.type === "12c" || H.type === "12c-platinum") {
if (self.reg_real("x") < 0 ||
self.reg_real("x") != Math.floor(self.reg_real("x"))) {
self.display_error(H.ERROR_DIVZERO);
return;
}
}
if (self.reg_real("x") > 69.95) {
self.save_lastx();
self.reg_Set_real("x", H.value_max);
self.display_result();
return;
}
var res;
if (H.type === "12c" || H.type === "12c-platinum") {
res = H.fatorial(self.reg_real("x"));
} else {
res = H.fatorial_gamma(self.reg_real("x"));
}
if (H.badnumber(res)) {
self.display_error(H.ERROR_DIVZERO);
return;
}
self.save_lastx();
self.reg_Set_real("x", res);
self.display_result();
};
Hp12c_machine.prototype.frac = function ()
{
var self = this;
if (self.matrix_in_reg("x")) {
self.display_error(H.ERROR_MATRIX_OP);
return;
}
self.save_lastx();
self.reg_Set_real("x", (Math.abs(self.reg_real("x")) -
Math.floor(Math.abs(self.reg_real("x")))) *
H.binary_sgn(self.reg_real("x")));
self.display_result();
};
Hp12c_machine.prototype.percent = function ()
{
var self = this;
if (self.matrix_in_reg("x") || self.matrix_in_reg("y")) {
self.display_error(H.ERROR_MATRIX_OP);
return;
}
var res = self.reg_real("y") * self.reg_real("x") / 100;
res = H.clamp(res);
self.save_lastx();
self.reg_Set_real("x", res);
self.display_result();
};
Hp12c_machine.prototype.deltapercent = function ()
{
var self = this;
if (self.matrix_in_reg("x") || self.matrix_in_reg("y")) {
self.display_error(H.ERROR_MATRIX_OP);
return;
}
if (! self.alg_resolve(1)) {
return;
}
var res = 100 * (self.reg_real("x") / self.reg_real("y")) - 100;
if (H.badnumber(res)) {
self.display_error(H.ERROR_DIVZERO);
} else {
self.save_lastx();
self.reg_Set_real("x", res);
self.display_result();
}
};
Hp12c_machine.prototype.sto = function (pos)
{
var self = this;
if (self.matrix_in_reg("x")) {
self.display_error(H.ERROR_MATRIX_OP);
return;
}
if (! self.alg_resolve(1)) {
return;
}
var res = 100 * (self.reg_real("x") / self.reg_real("y")) - 100;
// "pos" comes correctly adjusted from dispatcher even in the
// case of HP-16C (0..15, 16..31).
self.reg_To_sto("x", pos);
self.display_result_s(false, true);
};
Hp12c_machine.prototype.sto_index = function (pos)
{
var self = this;
if (self.matrix_in_index()) {
self.sto_matrix_el_i();
return;
}
var index = self.fix_index();
if (index === null) {
return;
}
self.reg_To_sto("x", index);
self.display_result_s(false, true);
};
Hp12c_machine.prototype.get_index = function ()
{
var self = this;
if (! self.pushed) {
self.push();
}
self.reg_Set_tuple("x", {r: self.index, h: self.indexh, i: 0});
self.display_result();
};
Hp12c_machine.prototype.set_index = function ()
{
var self = this;
var x = self.reg_tuple("x");
self.index = x.r;
self.indexh = x.h;
self.display_result();
};
Hp12c_machine.prototype.tarithmetic = function (at, bt, op)
{
var self = this;
// not implemented in 16c
var res = {};
res.r = res.i = res.h = 0;
if (op === "+") {
res.r = H.arithmetic_round(at.r + bt.r, at.r, bt.r);
} else if (op === "-") {
res.r = H.arithmetic_round(at.r - bt.r, at.r, bt.r);
} else if (op === "x") {
res.r = H.arithmetic_round(at.r * bt.r, 0, 0);
} else if (op === "/") {
res.r = H.arithmetic_round(at.r / bt.r, 0, 0);
}
return res;
};
Hp12c_machine.prototype.stoinfix_core = function (a, operation)
{
var self = this;
if (self.matrix_in_reg("x")) {
self.display_error(H.ERROR_MATRIX_OP);
return null;
}
var b = self.reg_tuple("x");
if (operation == H.STO_PLUS) {
a = self.tarithmetic(a, b, "+");
} else if (operation == H.STO_MINUS) {
a = self.tarithmetic(a, b, "-");
} else if (operation == H.STO_TIMES) {
a = self.tarithmetic(a, b, "x");
} else if (operation == H.STO_DIVIDE) {
a = self.tarithmetic(a, b, "/");
if (H.badnumber(a.r)) {
self.display_error(H.ERROR_DIVZERO);
return null;
}
}
a.r = H.clamp(a.r);
return a;
};
Hp12c_machine.prototype.rcl = function (pos)
{
var self = this;
if (! self.pushed) {
self.push();
}
self.sto_To_reg(pos, "x");
self.display_result(); // enables pushing
};
Hp12c_machine.prototype.rcl_index = function (pos)
{
var self = this;
if (self.matrix_in_index()) {
self.rcl_matrix_el_i();
return;
}
var index = self.fix_index();
if (index === null) {
return;
}
if (! self.pushed) {
self.push();
}
self.sto_To_reg(index, "x");
self.display_result(); // enables pushing
};
Hp12c_machine.prototype.stat_sigma_rcl = function ()
{
var self = this;
if (! self.pushed) {
self.push();
}
self.push();
self.sto_To_reg(H.STAT_X, "x");
self.sto_To_reg(H.STAT_Y, "y");
self.display_result();
};
Hp12c_machine.prototype.stat_sigma_plus = function ()
{
var self = this;
if (self.matrix_in_reg("x") || self.matrix_in_reg("y")) {
self.display_error(H.ERROR_MATRIX_OP);
return;
}
if (! self.alg_resolve(1)) {
return;
}
H.stat_accumulate(+1, self.sto_mem_ref(), self.reg_real("x"), self.reg_real("y"));
self.save_lastx();
self.sto_To_reg(H.STAT_N, "x");
self.display_result();
self.pushed = 1;
};
Hp12c_machine.prototype.stat_sigma_minus = function ()
{
var self = this;
if (self.matrix_in_reg("x") || self.matrix_in_reg("y")) {
self.display_error(H.ERROR_MATRIX_OP);
return;
}
if (! self.alg_resolve(1)) {
return;
}
H.stat_accumulate(-1, self.sto_mem_ref(), self.reg_real("x"), self.reg_real("y"));
self.save_lastx();
self.sto_To_reg(H.STAT_N, "x");
self.display_result();
self.pushed = 1;
};
Hp12c_machine.prototype.stat_avgw = function ()
{
var self = this;
if (H.type === "12c-platinum") {
self.algebra = [];
self.display_parentheses();
}
// 16C does not have statistics, so this is ok
var res = H.stat_avgw(self.sto_mem_ref());
if (! res[0]) {
self.display_error(H.ERROR_STAT);
} else {
self.save_lastx();
self.reg_Set_real("x", res[1]);
self.display_result();
}
};
Hp12c_machine.prototype.stat_avg = function ()
{
var self = this;
if (H.type === "12c-platinum") {
self.algebra = [];
self.display_parentheses();
}
var res = H.stat_avg(self.sto_mem_ref());
if (! res[0]) {
self.display_error(H.ERROR_STAT);
} else {
if (! self.pushed) {
self.push();
}
self.push();
self.reg_Set_real("x", res[1]);
self.reg_Set_real("y", res[2]);
self.display_result();
}
};
Hp12c_machine.prototype.stat_stddev = function ()
{
var self = this;
if (H.type === "12c-platinum") {
self.algebra = [];
self.display_parentheses();
}
var res = H.stddev(self.sto_mem_ref());
if (! res[0]) {
self.display_error(H.ERROR_STAT);
return;
}
if (! self.pushed) {
self.push();
}
self.push();
self.reg_Set_real("x", res[1]);
self.reg_Set_real("y", res[2]);
self.display_result();
};
Hp12c_machine.prototype.stat_lr = function (is_x)
{
var self = this;
if (self.matrix_in_reg("x")) {
self.display_error(H.ERROR_MATRIX_OP);
return null;
}
if (H.type === "12c-platinum") {
self.algebra = [];
self.display_parentheses();
}
var res = H.stat_kr(self.sto_mem_ref(), is_x, self.reg_real("x"));
if (! res[0]) {
self.display_error(H.ERROR_STAT);
} else {
self.save_lastx();
self.push();
self.reg_Set_real("x", res[1]);
self.reg_Set_real("y", res[2]);
self.display_result();
}
};
Hp12c_machine.prototype.stat_linearregression = function ()
{
var self = this;
// this method is called only for 11C and 15C
/*
if (H.type === "12c-platinum") {
self.algebra = [];
self.display_parentheses();
}
*/
var res = H.linear_regression(self.sto_mem_ref());
if (! res[0]) {
self.display_error(H.ERROR_STAT);
} else {
if (! self.pushed) {
self.push();
}
self.push();
self.reg_Set_real("x", res[1]); // B
self.reg_Set_real("y", res[2]); // A
self.display_result();
}
};
Hp12c_machine.prototype.permutations = function ()
{
var self = this;
if (self.matrix_in_reg("x")) {
self.matrix_zc_zp();
return;
}
var x = self.reg_real("x");
var y = self.reg_real("y");
if (x < 0 || x != Math.floor(x) || x >= 70 ||
y < 0 || y != Math.floor(y) || y >= 70 ||
y < x) {
self.display_error(H.ERROR_DIVZERO);
} else {
self.save_lastx();
var res = H.permutations(y, x);
self.pop();
self.reg_Set_real("x", res);
self.display_result();
}
};
Hp12c_machine.prototype.combinations = function ()
{
var self = this;
if (self.matrix_in_reg("x")) {
self.matrix_zp_zc();
return;
}
var x = self.reg_real("x");
var y = self.reg_real("y");
if (x < 0 || x != Math.floor(x) || x >= 70 ||
y < 0 || y != Math.floor(y) || y >= 70 ||
y < x) {
self.display_error(H.ERROR_DIVZERO);
} else {
self.save_lastx();
var res = H.combinations(y, x);
self.pop();
self.reg_Set_real("x", res);
self.display_result();
}
};
Hp12c_machine.prototype.display_program_opcode = function ()
{
var self = this;
var instr = self.ram[self.ip];
if (H.type === "16c") {
instr = H.pgrm.hex_opcode(instr);
} else if (H.type === "15c") {
instr = H.pgrm.shrunk_opcode(instr);
}
var txt = H.zeropad(self.ip.toFixed(0), H.ram_ADDR_SIZE) +
"-" + instr;
H.display.show_nopgrm(txt);
};
Hp12c_machine.prototype.prog_pr = function ()
{
var self = this;
if (H.type === "12c-platinum") {
self.algebra = [];
self.display_parentheses();
}
if (self.program_mode == H.INTERACTIVE) {
self.program_mode = H.PROGRAMMING;
// NOTE: entering programming mode does not reset instruction pointer
// self.ip = 0;
self.display_pgrm();
self.display_program_opcode();
}
};
Hp12c_machine.prototype.gto_digit_add = function (n)
{
var self = this;
if (n > 9) {
// possible only in 16c
self.display_error(H.ERROR_IMPROPER_N);
return;
}
if (H.type === "12c-platinum") {
self.algebra = [];
self.display_parentheses();
}
self.gtoxx = "" + self.gtoxx + n.toFixed(0);
if (self.gtoxx.length >= H.ram_ADDR_SIZE) {
var new_ip = parseInt(self.gtoxx, 10);
self.gtoxx = "";
self.rst_modifier(); // OK
if (new_ip > self.program_limit()) {
self.display_error(H.ERROR_IP);
return;
}
self.ip = new_ip;
}
};
Hp12c_machine.prototype.ntest = function (var1, criteria, var2, cplx)
{
var self = this;
var1 = self.reg_tuple(var1);
if (var2 !== "0") {
var2 = self.reg_tuple(var2);
} else {
var2 = {r: 0, h: 0, i: 0};
}
var res;
if (self.notation >= H.NOTATION_INT) {
if (criteria == "==" || criteria == "=" || criteria == "===") {
res = H.integer_eq(var1, var2, self.negative_repr, self.wordsize);
} else if (criteria == "<=") {
res = H.integer_le(var1, var2, self.negative_repr, self.wordsize);
} else if (criteria == "<") {
res = H.integer_lt(var1, var2, self.negative_repr, self.wordsize);
}
} else {
if (criteria == "==" || criteria == "=" || criteria == "===") {
res = H.feq10(var1.r, var2.r);
if (cplx && self.is_complex_mode()) {
res = res && H.feq10(var1.i, var2.i);
}
} else if (criteria == "<=") {
res = var1.r <= var2.r;
} else if (criteria == "<") {
res = var1.r < var2.r;
}
}
return res;
};
Hp12c_machine.prototype.test = function (condition)
{
var self = this;
self.display_result_s(false, true);
self.incr_ip(condition ? 0 : 1);
};
Hp12c_machine.prototype.test_x_le_y = function ()
{
var self = this;
self.test(self.ntest("x", "<=", "y"));
};
Hp12c_machine.prototype.test_x_gt_y = function ()
{
var self = this;
self.test(! self.ntest("x", "<=", "y"));
};
Hp12c_machine.prototype.test_x_eq_y = function ()
{
var self = this;
self.test(self.ntest("x", "==", "y", true));
};
Hp12c_machine.prototype.test_x_ne_y = function ()
{
var self = this;
self.test(! self.ntest("x", "==", "y", true));
};
Hp12c_machine.prototype.test_x_ge_y = function ()
{
var self = this;
self.test(! self.ntest("x", "<", "y"));
};
Hp12c_machine.prototype.test_x_lt_y = function ()
{
var self = this;
self.test(self.ntest("x", "<", "y"));
};
Hp12c_machine.prototype.test_x_less_0 = function ()
{
var self = this;
self.test(self.ntest("x", "<", "0"));
};
Hp12c_machine.prototype.test_x_ge_0 = function ()
{
var self = this;
self.test(! self.ntest("x", "<", "0"));
};
Hp12c_machine.prototype.test_x_gt_0 = function ()
{
var self = this;
self.test(! self.ntest("x", "<=", "0"));
};
Hp12c_machine.prototype.test_x_le_0 = function ()
{
var self = this;
self.test(self.ntest("x", "<=", "0"));
};
Hp12c_machine.prototype.test_x_eq0 = function ()
{
var self = this;
// works for matrix since x would be a non-zero descriptor
self.test(self.ntest("x", "==", "0", true));
};
Hp12c_machine.prototype.test_x_ne0 = function ()
{
var self = this;
self.test(! self.ntest("x", "==", "0", true));
};
Hp12c_machine.prototype.gto_buf_clear = function ()
{
var self = this;
self.gtoxx = "";
};
// not really executed, just to satisfy sentry/stop pseudoinstruction
Hp12c_machine.prototype.nop = function ()
{
};
Hp12c_machine.prototype.program_stopped = function (reason)
{
var self = this;
if (H.type !== "15c") {
return;
}
// handles result of subroutine execution for SOLVE,
// integration, etc.
self.pop_running_context(reason);
};
Hp12c_machine.prototype.get_complex = function ()
{
var self = this;
return self.flags[H.FLAG_COMPLEX];
};
Hp12c_machine.prototype.is_complex_mode = function ()
{
var self = this;
if (H.type === "15c") {
return self.get_complex();
}
return false;
};
Hp12c_machine.prototype.set_complex = function (v)
{
var self = this;
if (H.type === "15c") {
self.do_sf(H.FLAG_COMPLEX);
}
};
Hp12c_machine.prototype.set_overflow = function (v)
{
var self = this;
if (H.type === "16c" || H.type === "15c") {
if (v) {
self.do_sf(H.FLAG_OVERFLOW);
} else {
self.do_cf(H.FLAG_OVERFLOW);
}
}
};
Hp12c_machine.prototype.get_overflow = function ()
{
var self = this;
return self.flags[H.FLAG_OVERFLOW];
};
Hp12c_machine.prototype.matrix_in_reg = function (reg)
{
var self = this;
if (H.type !== "15c") {
return 0;
}
var x = self.reg_tuple(reg);
if ((! x.h) || (! self.chk_matrix_number(x.r))) {
return 0;
}
return x.r;
};
Hp12c_machine.prototype.matrix_in_index = function ()
{
var self = this;
if (H.type !== "15c") {
return 0;
}
if ((! self.indexh) || (! self.chk_matrix_number(self.index))) {
return 0;
}
return self.index;
};
Hp12c_machine.prototype.alg_resolve = function (close_all)
{
var self = this;
if (H.type !== "12c-platinum") {
return 1;
}
return self.alg_resolve_in(close_all);
};
Hp12c_machine.prototype.stoinfix = function (pos, operation)
{
var self = this;
var a;
if (pos === 99999) {
a = {r: self.index, i: 0, h: 0};
} else {
a = self.sto_tuple(pos);
}
a = self.stoinfix_core(a, operation);
if (a === null) {
return;
}
if (pos === 99999) {
self.index = a.r;
} else {
self.sto_Set_tuple(pos, a);
}
self.display_result();
};
Hp12c_machine.prototype.stoinfix_index = function (operation)
{
var self = this;
if (self.matrix_in_index()) {
self.sto_infix_matrix_el_i(operation);
return;
}
var index = self.fix_index();
if (index === null) {
return;
}
self.stoinfix(index, operation);
};
/*jslint white: true, undef: true, nomen: true, regexp: true, bitwise: true, strict: true, browser: true */
/*jshint globalstrict: true*/
/*global H, Hp12c_machine */
"use strict";
Hp12c_machine.prototype.display_result_date = function (dd)
{
var self = this;
if (H.type === "12c-platinum") {
self.algebra = [];
self.display_parentheses();
}
self.clear_typing();
H.display.show_date(H.date_to_show(dd, self.dmy));
};
Hp12c_machine.prototype.algebraic_mode = function ()
{
var self = this;
self.algmode = 1;
self.algebra = [];
self.display_parentheses();
self.display_algmode();
self.display_result();
};
Hp12c_machine.prototype.algebraic_open_parentheses = function ()
{
var self = this;
if (! self.algmode) {
return;
}
var count = self.count_open_parentheses();
if (count > 13) {
// maximum 13 parentheses
self.display_error(H.ERROR_IP);
return;
}
if (self.can_open_parentheses()) {
// e.g. "5 (" -- invalid
self.algebra.push("(");
window.xlog("(open) " + self.algebra.join(" "));
self.display_parentheses();
return;
}
};
Hp12c_machine.prototype.algebraic_close_parentheses = function ()
{
var self = this;
if (! self.algmode) {
return;
}
if (self.do_close_parentheses(0)) {
self.alg_resolve(0);
self.display_parentheses();
} else {
self.display_result();
}
};
Hp12c_machine.prototype.platinum_undo = function ()
{
var self = this;
var e;
if (self.undoable === self.UNDOABLE_CLX) {
self.reg_Set_real("x", self.undoable_assets);
self.display_result();
} else if (self.undoable === self.UNDOABLE_BSP) {
// currently not implemented (12c BSP does CLx?)
} else if (self.undoable === self.UNDOABLE_BSP_TYPING) {
self.xmode = self.undoable_assets[0];
self.typed_mantissa = self.undoable_assets[1];
self.typed_decimals = self.undoable_assets[2];
self.typed_exponent = self.undoable_assets[3];
self.typed_mantissa_signal = self.undoable_assets[4];
self.typed_exponent_signal = self.undoable_assets[5];
self.display_typing();
} else if (self.undoable === self.UNDOABLE_CLEAR_REG) {
for (e = 0; e < 5; ++e) {
self.finmemory[e] = self.undoable_assets.fin[e];
}
for (e = 0; e < H.MEM_MAX; ++e) {
self.sto_Set_tuple(e, self.undoable_assets.sto[e]);
}
for (e = 0; e < H.MEM_MAX; ++e) {
self.njmemory[e] = self.undoable_assets.nj[e];
}
self.reg_Set_real("x", self.undoable_assets.stack.x);
self.reg_Set_real("y", self.undoable_assets.stack.y);
self.reg_Set_real("z", self.undoable_assets.stack.z);
self.reg_Set_real("w", self.undoable_assets.stack.w);
self.reg_Set_real("last_x", self.undoable_assets.stack.last_x);
self.display_result();
} else if (self.undoable === self.UNDOABLE_CLEAR_STAT) {
for (e = H.STAT_MIN; e <= H.STAT_MAX; ++e) {
self.sto_Set_tuple(e, self.undoable_assets.sto[e]);
}
self.reg_Set_real("x", self.undoable_assets.stack.x);
self.reg_Set_real("y", self.undoable_assets.stack.y);
self.reg_Set_real("z", self.undoable_assets.stack.z);
self.reg_Set_real("w", self.undoable_assets.stack.w);
self.display_result();
} else if (self.undoable === self.UNDOABLE_CLEAR_FIN) {
for (e = 0; e < 5; ++e) {
self.finmemory[e] = self.undoable_assets[e];
}
self.display_result();
}
self.undoable = self.UNDOABLE_NONE;
self.undoable_assets = null;
self.display_undo();
};
Hp12c_machine.prototype.algebra_rightmost_is_number = function ()
{
var self = this;
if (self.algebra.length <= 0) {
return false;
}
return typeof self.algebra[self.algebra.length - 1] === "number";
};
Hp12c_machine.prototype.can_open_parentheses = function ()
{
var self = this;
if (self.algebra.length <= 0) {
// can always begin a sentence with (
return 1;
}
var rightmost = self.algebra[self.algebra.length - 1];
if (typeof rightmost === "string") {
if (rightmost !== ")") {
// "... 5 x (" or "... 5 x ( ("
return 1;
} else {
// "... ) (" forbidden
return 0;
}
}
// forbidden seq. like "... 5 ("
return 0;
};
Hp12c_machine.prototype.count_open_parentheses = function ()
{
var self = this;
var open = 0;
for (var i = 0; i < self.algebra.length; ++i) {
var token = self.algebra[i];
if (typeof token !== "string") {
continue;
}
if (token === "(") {
++open;
} else if (token === ")") {
--open;
}
}
return open;
};
Hp12c_machine.prototype.do_close_parentheses = function ()
{
var self = this;
var open = self.count_open_parentheses();
if (open > 0) {
var rightmost = self.algebra[self.algebra.length - 1];
if (typeof rightmost === "string") {
if (rightmost !== ")") {
// "... 5 x" or "... 5 x ("
// takes another numeric parameter so it becomes
// "... 5 x n )" or "... 5 x ( n )"
self.algebra.push(self.reg_real("x"));
}
}
self.algebra.push(")");
window.xlog("(close) " + self.algebra.join(" "));
}
return open > 0;
};
Hp12c_machine.prototype.alg_resolve_in = function (close_all)
{
var self = this;
// 12C-only algebric mode.
var res;
var ok = 1;
if (! self.algmode) {
return ok;
}
// add X value if rightmost item is an operator
if (self.algebra.length > 0) {
var rightmost = self.algebra[self.algebra.length - 1];
if (typeof rightmost === "string") {
if (rightmost !== ")") {
// "... 5 x" or "... 5 x ("
// takes another numeric parameter so it becomes
// "... 5 x n )" or "... 5 x ( n )"
self.algebra.push(self.reg_real("x"));
}
}
}
if (close_all) {
while (self.do_close_parentheses(1)) {
}
}
window.xlog("--- solving " + (close_all ? "all" : "one"));
ok = self.do_alg_solve(close_all);
self.display_parentheses();
return ok;
};
Hp12c_machine.prototype.do_alg_solve = function (close_all)
{
var self = this;
var ok = 1;
if (self.algebra.length <= 0) {
window.xlog("Nothing to solve");
return ok;
}
var solved = 1;
var did_solve = 0;
while (true) {
if (self.algebra.length > 0) {
window.xlog(self.algebra.join(" "));
} else {
window.xlog("--");
}
// delay break to show algebra before quitting
if (! solved || ! ok || (did_solve && ! close_all)) {
break;
}
var res_array = self.do_alg_solve_in();
var res = res_array[0];
solved = res_array[1];
if (H.badnumber(res)) {
ok = 0;
self.display_error(H.ERROR_DIVZERO);
self.algebra = [];
} else if (solved) {
did_solve = 1;
// if there is some error in another op, x gets the
// value of last solved operation
self.reg_Set_real("x", res);
}
}
if (ok && did_solve) {
var x = self.reg_real("x");
self.finish_arithmetic(x, x, x);
}
if (close_all) {
self.algebra = [];
}
return ok;
};
Hp12c_machine.prototype.do_alg_simplify = function ()
{
var self = this;
// look for "( number )" to simplify
for (var i = self.algebra.length - 3; i >= 0; --i) {
var nu = self.do_alg_simplify_in(i);
if (typeof nu === "number") {
return nu;
}
}
return null;
};
Hp12c_machine.prototype.do_alg_simplify_in = function (i)
{
var self = this;
if (i < 0 || (i + 2) >= self.algebra.length) {
return null;
}
var op = self.algebra[i];
var nu = self.algebra[i + 1];
var cp = self.algebra[i + 2];
if (typeof op !== "string" || typeof nu !== "number" ||
typeof cp !== "string") {
return null;
}
if (op !== "(" || cp !== ")") {
return null;
}
// found opportunity to simplify
self.algebra.splice(i, 3, nu);
return nu;
};
Hp12c_machine.prototype.do_alg_solve_in = function ()
{
var self = this;
var i, nu, op, a, b, cp;
// trivial case: empty list
if (self.algebra.length <= 0) {
return [0, false];
}
// trivial case: single number
if (self.algebra.length === 1) {
nu = self.algebra[0];
if (typeof nu === "number") {
self.algebra = [];
return [nu, true];
}
}
nu = self.do_alg_simplify();
if (typeof nu === "number") {
return [nu, true];
}
// look for "x op y" to solve
for (i = self.algebra.length - 3; i >= 0; --i) {
a = self.algebra[i];
op = self.algebra[i + 1];
b = self.algebra[i + 2];
if (typeof a !== "number" || typeof op !== "string" ||
typeof b !== "number") {
continue;
}
var res;
if (op === "+") {
res = H.arithmetic_round(a + b, a, b);
self.algebra.splice(i, 3, res);
self.do_alg_simplify_in(i - 1);
return [res, true];
} else if (op === "-") {
res = H.arithmetic_round(a - b, a, b);
self.algebra.splice(i, 3, res);
self.do_alg_simplify_in(i - 1);
return [res, true];
} else if (op === "*") {
res = H.arithmetic_round(a * b, 0, 0);
self.algebra.splice(i, 3, res);
self.do_alg_simplify_in(i - 1);
return [res, true];
} else if (op === "/") {
res = a / b;
if (! H.badnumber(res)) {
res = H.arithmetic_round(res, 0, 0);
}
self.algebra.splice(i, 3, res);
self.do_alg_simplify_in(i - 1);
return [res, true];
} else if (op === "^") {
res = Math.pow(a, b);
if (a === 0 && b === 0) {
res = NaN;
}
if (! H.badnumber(res)) {
res = H.arithmetic_round(res, 0, 0);
}
self.algebra.splice(i, 3, res);
self.do_alg_simplify_in(i - 1);
return [res, true];
} else {
// inconsistent (should not happen)
self.algebra = [];
return [b, false];
}
}
// nothing to do
return [0, false];
};
Hp12c_machine.prototype.stoCF0 = function ()
{
var self = this;
if (! self.alg_resolve(1)) {
return;
}
var res = 100 * (self.reg_real("x") / self.reg_real("y")) - 100;
self.reg_To_sto("x", 0);
self.finmemory[H.FIN_N] = 0;
self.display_result();
};
Hp12c_machine.prototype.stoCFj = function ()
{
var self = this;
if (! self.alg_resolve(1)) {
return;
}
var res = 100 * (self.reg_real("x") / self.reg_real("y")) - 100;
if (self.finmemory[H.FIN_N] != Math.floor(self.finmemory[H.FIN_N]) ||
self.finmemory[H.FIN_N] < 0 ||
self.finmemory[H.FIN_N] >= H.MEM_MAX) {
self.display_error(H.ERROR_MEMORY);
} else {
self.finmemory[H.FIN_N]++;
self.reg_To_sto("x", self.finmemory[H.FIN_N]);
self.njmemory[self.finmemory[H.FIN_N]] = 1;
self.display_result();
}
};
Hp12c_machine.prototype.rclCFj = function ()
{
var self = this;
if (self.finmemory[H.FIN_N] < 0 ||
self.finmemory[H.FIN_N] >= H.MEM_MAX ||
Math.floor(self.finmemory[H.FIN_N]) != self.finmemory[H.FIN_N]) {
self.display_error(H.ERROR_MEMORY);
} else {
if (! self.pushed) {
self.push();
}
self.sto_To_reg(self.finmemory[H.FIN_N], "x");
--self.finmemory[H.FIN_N];
self.display_result();
}
};
Hp12c_machine.prototype.rclNj = function ()
{
var self = this;
if (self.finmemory[H.FIN_N] < 0 ||
self.finmemory[H.FIN_N] >= H.MEM_MAX ||
Math.floor(self.finmemory[H.FIN_N]) != self.finmemory[H.FIN_N]) {
self.display_error(H.ERROR_MEMORY);
} else {
if (! self.pushed) {
self.push();
}
self.reg_Set_real("x", self.njmemory[self.finmemory[H.FIN_N]]);
self.display_result();
}
};
Hp12c_machine.prototype.stoNj = function ()
{
var self = this;
if (! self.alg_resolve(1)) {
return;
}
var res = 100 * (self.reg_real("x") / self.reg_real("y")) - 100;
if (self.finmemory[H.FIN_N] != Math.floor(self.finmemory[H.FIN_N]) ||
self.finmemory[H.FIN_N] <= 0 ||
self.finmemory[H.FIN_N] >= H.MEM_MAX ||
self.reg_real("x") != Math.floor(self.reg_real("x")) ||
self.reg_real("x") < 0 ||
self.reg_real("x") > 500) {
self.display_error(H.ERROR_MEMORY);
} else {
self.njmemory[self.finmemory[H.FIN_N]] = self.reg_real("x");
self.display_result();
}
};
Hp12c_machine.prototype.stofin = function (pos)
{
var self = this;
self.finmemory[pos] = self.reg_real("x");
self.display_result();
self.pushed = 1;
self.do_fincalc = 1; // next fin. key runs calculation
};
Hp12c_machine.prototype.ston_12x = function ()
{
var self = this;
if (! self.alg_resolve(1)) {
return;
}
var res = self.reg_real("x") * 12;
if (Math.abs(res) > H.value_max) {
self.display_error(H.ERROR_OVERFLOW);
return;
}
self.reg_Set_real("x", res);
self.stofin(0);
};
Hp12c_machine.prototype.stoi_12div = function ()
{
var self = this;
if (! self.alg_resolve(1)) {
return;
}
self.reg_Set_real("x", self.reg_real("x") / 12);
self.stofin(1);
};
Hp12c_machine.prototype.rclfin = function (pos, twelve)
{
var self = this;
if (! self.pushed) {
self.push();
}
var x = self.finmemory[pos];
if (twelve) {
if (pos === 0) {
// 12x n
x /= 12;
} else if (pos === 1) {
// 12/ i
x *= 12;
}
}
self.reg_Set_real("x", x);
self.display_result();
};
Hp12c_machine.prototype.simple_interest = function ()
{
var self = this;
if (! self.alg_resolve(1)) {
return;
}
var n = self.finmemory[H.FIN_N];
var i = self.finmemory[H.FIN_I] / 100;
var pv = self.finmemory[H.FIN_PV];
self.push();
self.push();
self.push();
self.reg_Set_real("x", n / 360 * -pv * i);
self.reg_Set_real("y", -pv);
self.reg_Set_real("z", n / 365 * -pv * i);
self.display_result();
};
Hp12c_machine.prototype.sto_or_calc_fin = function (pos)
{
var self = this;
if (! self.alg_resolve(1)) {
return;
}
if (! self.do_fincalc) {
self.stofin(pos);
} else {
H.display.show_running();
self.cli("sto_or_calc_fin");
self.enter_modal(H.MODAL_MISC);
H.delay(function () {
self.sti("sto_or_calc_fin");
self.reset_modal();
var err = H.financecalc(pos, self.begin, self.compoundf, self.finmemory);
if (err == -1) {
// no error
self.reg_Set_real("x", self.finmemory[pos]);
self.display_result();
} else {
self.display_error(err);
}
}, (self.rapid ? 0 : 200));
}
};
Hp12c_machine.prototype.npv = function ()
{
var self = this;
if (H.type === "12c-platinum") {
self.algebra = [];
self.display_parentheses();
}
if (! self.pushed) {
self.push();
}
// 16C does not have finance, so this is ok
self.reg_Set_real("x", H.npv(self.finmemory[H.FIN_N], self.finmemory[H.FIN_I], self.sto_mem_ref(), self.njmemory));
self.finmemory[H.FIN_PV] = self.x;
self.display_result();
};
Hp12c_machine.prototype.irr = function ()
{
var self = this;
if (H.type === "12c-platinum") {
self.algebra = [];
self.display_parentheses();
}
H.display.show_running();
self.cli("irr");
self.enter_modal(H.MODAL_MISC);
H.delay(function () {
self.sti("irr");
self.reset_modal();
var res = H.irr_calc(self.finmemory[H.FIN_N], self.finmemory[H.FIN_I],
self.sto_mem_ref(), self.njmemory);
var err = res[0];
self.finmemory[H.FIN_I] = res[1];
if (err != -1) {
self.display_error(err);
} else {
if (! self.pushed) {
self.push();
}
self.reg_Set_real("x", self.finmemory[H.FIN_I]);
self.display_result();
}
}, (self.rapid ? 0 : 200));
};
Hp12c_machine.prototype.date_date = function ()
{
var self = this;
if (H.type === "12c-platinum") {
self.algebra = [];
self.display_parentheses();
}
var base = H.date_interpret(self.reg_real("y"), self.dmy);
if (base === null) {
self.display_error(H.ERROR_DATE);
return;
}
self.save_lastx();
H.date_add(base, self.reg_real("x"));
self.pop(); // eat original arguments
self.reg_Set_real("x", H.date_gen(base, self.dmy)); // and fill with newly calculated date
self.display_result_date(base);
if (self.program_mode >= H.RUNNING) {
// in a program, 12C pauses so the date can be seen
self.cli("date");
self.enter_modal(H.MODAL_PAUSE);
H.delay(function () {
self.sti("date");
self.reset_modal();
}, 1000);
}
};
Hp12c_machine.prototype.date_dys = function ()
{
var self = this;
if (H.type === "12c-platinum") {
self.algebra = [];
self.display_parentheses();
}
var d2 = H.date_interpret(self.reg_real("x"), self.dmy);
var d1 = H.date_interpret(self.reg_real("y"), self.dmy);
if ((d1 === null) || (d2 === null)) {
self.display_error(H.ERROR_DATE);
return;
}
self.save_lastx();
self.reg_Set_real("x", H.date_diff(d1, d2));
self.reg_Set_real("y", H.date_diff30(d1, d2));
self.display_result();
};
Hp12c_machine.prototype.amortization = function ()
{
var self = this;
if (H.type === "12c-platinum") {
self.algebra = [];
self.display_parentheses();
}
var requested_n = self.reg_real("x");
var orig_n = self.finmemory[H.FIN_N];
var i = self.finmemory[H.FIN_I] / 100;
// AMORT rounds present value to shown decimals
var pv = H.cl5_round(self.finmemory[H.FIN_PV], self.decimals);
self.finmemory[H.FIN_PV] = pv;
// AMORT rounds payment to shown decimals
var pmt = H.cl5_round(self.finmemory[H.FIN_PMT], self.decimals);
self.finmemory[H.FIN_PMT] = pmt;
var res = H.amortization(requested_n, orig_n, i, pv, pmt, self.decimals, self.begin);
var err = res[0];
var tot_interest = res[1];
var tot_amort = res[2];
self.push();
self.push();
self.reg_Set_real("x", tot_interest);
self.reg_Set_real("y", tot_amort);
self.reg_Set_real("z", requested_n);
self.finmemory[H.FIN_N] += requested_n;
self.finmemory[H.FIN_PV] += tot_amort;
self.display_result();
};
Hp12c_machine.prototype.bond_price = function ()
{
var self = this;
if (H.type === "12c-platinum") {
self.algebra = [];
self.display_parentheses();
}
var desired_rate = self.finmemory[H.FIN_I];
if (desired_rate <= -100) {
self.display_error(H.ERROR_INTEREST);
return;
}
var coupon_year = self.finmemory[H.FIN_PMT];
var buy = H.date_interpret(self.reg_real("y"), self.dmy);
if (buy === null) {
self.display_error(H.ERROR_DATE);
return;
}
var maturity = H.date_interpret(self.reg_real("x"), self.dmy);
if (maturity === null) {
self.display_error(H.ERROR_DATE);
return;
}
var res = H.bond_price(desired_rate, coupon_year, buy, maturity);
if (res[0] >= 0) {
self.display_error(res[0]);
return;
}
self.push();
self.push();
self.finmemory[H.FIN_N] = res[1];
self.reg_Set_real("x", res[1]);
self.reg_Set_real("y", res[2]);
self.display_result();
};
Hp12c_machine.prototype.bond_yield = function ()
{
var self = this;
if (H.type === "12c-platinum") {
self.algebra = [];
self.display_parentheses();
}
var coupon_year = self.finmemory[H.FIN_PMT];
var buy = H.date_interpret(self.reg_real("y"), self.dmy);
var maturity = H.date_interpret(self.reg_real("x"), self.dmy);
var price = self.finmemory[H.FIN_PV];
var res = H.bond_yield(coupon_year, buy, maturity, price);
var err = res[0];
var desired_rate = res[1];
if (err >= 0) {
self.display_error(err);
return;
}
self.push();
self.finmemory[H.FIN_I] = desired_rate;
self.reg_Set_real("x", desired_rate);
self.display_result();
};
Hp12c_machine.prototype.depreciation_sl = function ()
{
var self = this;
if (H.type === "12c-platinum") {
self.algebra = [];
self.display_parentheses();
}
var cost = self.finmemory[H.FIN_PV];
var sell = self.finmemory[H.FIN_FV];
var life = self.finmemory[H.FIN_N];
var year = self.reg_real("x");
var res = H.depreciation_sl(cost, sell, life, year);
var err = res[0];
var depr = res[1];
var rest = res[2];
if (err >= 0) {
self.display_error(err);
return;
}
self.push();
self.push();
self.reg_Set_real("x", depr);
self.reg_Set_real("y", rest);
self.display_result();
};
Hp12c_machine.prototype.depreciation_soyd = function ()
{
var self = this;
if (H.type === "12c-platinum") {
self.algebra = [];
self.display_parentheses();
}
var cost = self.finmemory[H.FIN_PV];
var sell = self.finmemory[H.FIN_FV];
var life = self.finmemory[H.FIN_N];
var year = self.reg_real("x");
var res = H.depreciation_soyd(cost, sell, life, year);
var err = res[0];
var depr = res[1];
var rest = res[2];
if (err >= 0) {
self.display_error(err);
return;
}
self.push();
self.push();
self.reg_Set_real("x", depr);
self.reg_Set_real("y", rest);
self.display_result();
};
Hp12c_machine.prototype.depreciation_db = function ()
{
var self = this;
if (H.type === "12c-platinum") {
self.algebra = [];
self.display_parentheses();
}
var cost = self.finmemory[H.FIN_PV];
var sell = self.finmemory[H.FIN_FV];
var life = self.finmemory[H.FIN_N];
var year = self.reg_real("x");
var db = self.finmemory[H.FIN_I] / 100;
var res = H.depreciation_db(cost, sell, life, year, db);
var err = res[0];
var depr = res[1];
var rest = res[2];
if (err >= 0) {
self.display_error(err);
return;
}
self.push();
self.push();
self.reg_Set_real("x", depr);
self.reg_Set_real("y", rest);
self.display_result();
};
Hp12c_machine.prototype.percentT = function ()
{
var self = this;
if (! self.alg_resolve(1)) {
return;
}
var res = 100 * self.reg_real("x") / self.reg_real("y");
if (H.badnumber(res)) {
self.display_error(H.ERROR_DIVZERO);
} else {
self.save_lastx();
self.reg_Set_real("x", res);
self.display_result();
}
};
Hp12c_machine.prototype.bs_rho = function ()
{
var self = this;
var bsdata = self.finmemory.slice();
var res = H.bs_rho(bsdata);
var err = res[0];
var c = res[1];
var p = res[2];
if (err) {
self.display_error(H.ERROR_DIVZERO);
return;
}
self.push();
self.push();
self.reg_Set_real("x", c);
self.reg_Set_real("y", p);
self.display_result();
};
Hp12c_machine.prototype.bs_theta = function ()
{
var self = this;
var bsdata = self.finmemory.slice();
var res = H.bs_theta(bsdata);
var err = res[0];
var c = res[1];
var p = res[2];
if (err) {
self.display_error(H.ERROR_DIVZERO);
return;
}
self.push();
self.push();
self.reg_Set_real("x", c);
self.reg_Set_real("y", p);
self.display_result();
};
Hp12c_machine.prototype.bs_delta = function ()
{
var self = this;
var bsdata = self.finmemory.slice();
var res = H.bs_delta(bsdata);
var err = res[0];
var c = res[1];
var p = res[2];
if (err) {
self.display_error(H.ERROR_DIVZERO);
return;
}
self.push();
self.push();
self.reg_Set_real("x", c);
self.reg_Set_real("y", p);
self.display_result();
};
Hp12c_machine.prototype.bs_vega = function ()
{
var self = this;
var bsdata = self.finmemory.slice();
var res = H.bs_vega(bsdata);
var err = res[0];
var c = res[1];
var p = res[2];
if (err) {
self.display_error(H.ERROR_DIVZERO);
return;
}
self.push();
self.push();
self.reg_Set_real("x", c);
self.reg_Set_real("y", p);
self.display_result();
};
Hp12c_machine.prototype.bs_gamma = function ()
{
var self = this;
var bsdata = self.finmemory.slice();
var res = H.bs_gamma(bsdata);
var err = res[0];
var c = res[1];
var p = res[2];
if (err) {
self.display_error(H.ERROR_DIVZERO);
return;
}
self.push();
self.push();
self.reg_Set_real("x", c);
self.reg_Set_real("y", p);
self.display_result();
};
Hp12c_machine.prototype.bs_premium = function ()
{
var self = this;
var bsdata = self.finmemory.slice();
var res = H.bs_premium(bsdata);
var err = res[0];
var c = res[1];
var p = res[2];
if (err) {
self.display_error(H.ERROR_DIVZERO);
return;
}
self.push();
self.push();
self.reg_Set_real("x", c);
self.reg_Set_real("y", p);
self.display_result();
};
Hp12c_machine.prototype.bs_d1 = function ()
{
var self = this;
var bsdata = self.finmemory.slice();
var res = H.bs_d1(bsdata);
var err = res[0];
var c = res[1];
if (err) {
self.display_error(H.ERROR_DIVZERO);
return;
}
self.push();
self.reg_Set_real("x", c);
self.display_result();
};
Hp12c_machine.prototype.bs_d2 = function ()
{
var self = this;
var bsdata = self.finmemory.slice();
var res = H.bs_d2(bsdata);
var err = res[0];
var c = res[1];
if (err) {
self.display_error(H.ERROR_DIVZERO);
return;
}
self.push();
self.reg_Set_real("x", c);
self.display_result();
};
Hp12c_machine.prototype.bs_normal = function ()
{
var self = this;
var res = H.bs_normal(self.reg_real("x"));
self.save_lastx();
self.reg_Set_real("x", res);
self.display_result();
};
Hp12c_machine.prototype.bs_implvolC = function ()
{
var self = this;
var bsdata = self.finmemory.slice();
var res = H.bs_implvolC(bsdata, self.reg_real("x"));
var err = res[0];
var c = res[1];
if (err) {
self.display_error(H.ERROR_DIVZERO);
return;
}
self.save_lastx();
self.reg_Set_real("x", c);
self.display_result();
};
Hp12c_machine.prototype.bs_implvolP = function ()
{
var self = this;
var bsdata = self.finmemory.slice();
var res = H.bs_implvolP(bsdata, self.reg_real("x"));
var err = res[0];
var c = res[1];
if (err) {
self.display_error(H.ERROR_DIVZERO);
return;
}
self.save_lastx();
self.reg_Set_real("x", c);
self.display_result();
};
Hp12c_machine.prototype.bs_cumul = function ()
{
var self = this;
var res = H.bs_cumul(self.reg_real("x"));
self.save_lastx();
self.reg_Set_real("x", res);
self.display_result();
};
Hp12c_machine.prototype.bs_252div = function ()
{
var self = this;
var res = self.reg_real("x") / 252;
self.reg_Set_real("x", res);
self.stofin(0);
};
Hp12c_machine.prototype.bs_365div = function ()
{
var self = this;
var res = self.reg_real("x") / 365;
self.reg_Set_real("x", res);
self.stofin(0);
};
Hp12c_machine.prototype.bs_dys252 = function ()
{
var self = this;
var d2 = H.date_interpret(self.reg_real("x"), self.dmy);
var d1 = H.date_interpret(self.reg_real("y"), self.dmy);
if ((d1 === null) || (d2 === null)) {
self.display_error(H.ERROR_DATE);
return;
}
// does not eat Y to keep 'compatibility' with DYS
self.save_lastx();
self.reg_Set_real("x", H.date_diff252(d1, d2));
self.display_result();
};
/*jslint white: true, undef: true, nomen: true, regexp: true, strict: true, browser: true, bitwise: true */
/*jshint globalstrict: true*/
/*global H, Hp12c_dispatcher */
"use strict";
function Hp12c_dispatcher()
{
}
/*jslint white: true, undef: true, nomen: true, regexp: true, strict: true, browser: true, bitwise: true */
/*jshint globalstrict: true*/
/*global H, Hp12c_dispatcher */
"use strict";
// overridden by 12C and 16C flavors
Hp12c_dispatcher.prototype.handle_modifier = function (key, pgrm_mode, exec_mode)
{
var self = this;
var modifier_table = self.modifier_sm[key];
var f = self.find_function(key, 0, 1, exec_mode);
if (H.type !== "15c") {
if (H.machine.modifier == H.STO_FF || H.machine.modifier == H.RCL_FF) {
// this is always final, no modifier here
return false;
}
}
if (modifier_table) {
var next_modifier = modifier_table[H.machine.modifier];
if (next_modifier) {
// a modifier potentialized by a previous one
H.machine.set_modifier(next_modifier);
return true;
} else if (modifier_table[0] && !f) {
// a modifier of its own right, like f, g
H.machine.set_modifier(modifier_table[0]);
return true;
}
}
return false;
};
// overridden by 12C and 16C flavors
Hp12c_dispatcher.prototype.find_function = function (key, pgrm_mode, query, exec_mode)
{
var self = this;
var function_table = self.functions[key];
var f = null;
if (!function_table) {
return null;
}
f = function_table[H.machine.modifier];
if (f) {
if (f.reducible) {
// Handle cases like STO PLUS f I, STO f I
// make opcode like STO I and STO PLUS I
H.machine.set_modifier(f.reduced_modifier);
f = function_table[H.machine.modifier];
}
}
if (!f) {
// no function given current modifier
if (query === 1) {
return null;
}
if (H.machine.modifier == H.STO_FF ||
H.machine.modifier == H.RCL_FF ||
H.machine.modifier == H.STO_PLUS_FF ||
H.machine.modifier == H.STO_MINUS_FF ||
H.machine.modifier == H.STO_TIMES_FF ||
H.machine.modifier == H.STO_DIVIDE_FF) {
// give a chance to plain F
f = function_table[H.FF];
if (f && query === 0) {
H.machine.set_modifier(H.FF);
}
}
}
if (!f) {
// try plain key without any modifier
f = function_table[0];
if (f && query === 0) {
H.machine.rst_modifier(1);
}
}
if (pgrm_mode && f && f.no_pgrm) {
// this function can not be programmed; revoked
f = null;
}
return f;
};
// Used by all flavors
Hp12c_dispatcher.prototype.dispatch_basic = function (key)
{
var self = this;
// 'special' keys that do not belong to calculator itself
if (key == 99) {
H.debug.show_memory();
return true;
} else if (key === 200) {
self.lcd_left();
return true;
} else if (key === 201) {
self.lcd_right();
return true;
}
if (H.machine.program_mode === H.RUNNING_STEP_PRE) {
H.pgrm.run_step_finish();
return true;
} else if (H.machine.modal() > 0) {
H.machine.reset_modal();
return true;
} else if (H.machine.program_mode >= H.RUNNING) {
H.pgrm.stop(1);
return true;
}
return false;
};
// overridden by 12C and 16C flavors
Hp12c_dispatcher.prototype.dispatch = function (key)
{
var self = this;
if (self.dispatch_basic(key)) {
return;
}
// Determine key function early, because we need that in USER logic
var f_mod = self.find_function(key, 0, 1, false);
var f = f_mod;
var tmp = H.machine.modifier;
if (!f) {
H.machine.modifier = 0;
f = self.find_function(key, 0, 1, false);
H.machine.modifier = tmp;
}
// USER logic - may change modifier
if (key >= 11 && key <= 15) {
if (H.machine.user) {
if (H.machine.modifier == H.FF) {
// USER + f = natural
H.machine.modifier = 0;
} else if (H.machine.modifier == H.STO_FF ||
H.machine.modifier == H.RCL_FF ||
H.machine.modifier == H.STO_PLUS_FF ||
H.machine.modifier == H.STO_MINUS_FF ||
H.machine.modifier == H.STO_TIMES_FF ||
H.machine.modifier == H.STO_DIVIDE_FF) {
// USER + f = natural
H.machine.modifier = 0;
} else if (H.machine.modifier === 0) {
// USER + no modifier = f
H.machine.modifier = H.FF;
} else if (! f_mod) {
// USER + invalid modifier -> f
H.machine.modifier = H.FF;
}
// GSB [A-F] and GTO [A-F] not affected because
// GSB and GTO are modifiers different from the ones
// handled above.
} else {
// natural course
}
}
// Programming mode?
if (H.machine.program_mode == H.PROGRAMMING) {
H.pgrm.type(key);
return;
}
self.dispatch_common(key, false);
};
// overridden by 12C and 16C flavors
Hp12c_dispatcher.prototype.dispatch_common = function (key, in_exec)
{
var self = this;
var ok = 1;
if (self.handle_modifier(key, 0, in_exec)) {
return ok;
}
// key is not modifier in this context, try a function
var f = self.find_function(key, 0, 0, in_exec);
if (!f) {
// no-op
f = function () { };
ok = false;
}
var rst_modifier = 1;
if (f.dont_rst_modifier) {
rst_modifier = 0;
}
f();
if (rst_modifier) {
H.machine.rst_modifier(1);
}
return ok;
};
// overridden when touching LCD is to have some collateral effect
Hp12c_dispatcher.prototype.lcd_left = function ()
{
var self = this;
window.xlog("LCD left side touched " + H.format_result_clipboard());
};
// overridden when touching LCD is to have some collateral effect
Hp12c_dispatcher.prototype.lcd_right = function ()
{
var self = this;
window.xlog("LCD right side touched " + H.format_result_clipboard());
};
// overridden by mobile versions
Hp12c_dispatcher.prototype.log_opcode = function (opcode) {
var self = this;
// no need to pollute the unittest log with 10000s of messages
var _ = (typeof UT === "undefined") && window.xlog("op " + opcode);
};
/*jslint white: true, undef: true, nomen: true, regexp: true, strict: true, browser: true, bitwise: true */
/*global H, Hp12c_machine, Hp12c_dispatcher */
/*jshint globalstrict: true*/
"use strict";
// aliases to function and modifier arrays;
var K = [];
var M = [];
var I;
Hp12c_dispatcher.prototype.functions = K;
Hp12c_dispatcher.prototype.modifier_sm = M;
Hp12c_dispatcher.prototype.KEY_RS = 31;
Hp12c_dispatcher.prototype.KEY_SST = 32;
Hp12c_dispatcher.prototype.KEY_RDOWN = 33;
H.FF = Hp12c_dispatcher.prototype.KEY_FF = 42;
H.GG = Hp12c_dispatcher.prototype.KEY_GG = 43;
H.STO = Hp12c_dispatcher.prototype.KEY_STO = 44;
H.RCL = Hp12c_dispatcher.prototype.KEY_RCL = 45;
Hp12c_dispatcher.prototype.KEY_DECIMAL = 48;
Hp12c_dispatcher.prototype.KEY_PLUS = 40;
Hp12c_dispatcher.prototype.KEY_MINUS = 30;
Hp12c_dispatcher.prototype.KEY_MULTIPLY = 20;
Hp12c_dispatcher.prototype.KEY_DIVIDE = 10;
Hp12c_dispatcher.prototype.KEY_BACKSPACE = 98;
H.STO2 = H.STO * 100 + 48;
H.RCL2 = H.RCL * 100 + 48;
H.RCL_GG = H.RCL * 100 + H.GG;
H.STO_PLUS = H.STO * 100 + 40;
H.STO_MINUS = H.STO * 100 + 30;
H.STO_TIMES = H.STO * 100 + 20;
H.STO_DIVIDE = H.STO * 100 + 10;
H.GTO = H.GG * 100 + 33;
// program typing mode only
H.GTO_MOVE = H.GTO * 100 + 48;
// does not exist in 12c
H.HYP = H.HYPINV = H.LBL = H.GSB = H.FIX = H.SCI = H.ENG = H.STO_F = 99999999;
Hp12c_dispatcher.init_vars = function () {
var Keys = [11, 12, 13, 14, 15, 16, 7, 8, 9, 10,
21, 22, 23, 24, 25, 26, 4, 5, 6, 20,
31, 32, 33, 34, 35, 36, 1, 2, 3, 30,
41, 42, 43, 44, 45, 0, 48, 49, 40,
98];
var Modifiers = [H.FF, H.GG, H.STO, H.RCL, 48, 10, 20, 30, 40, 33];
var i;
for (i = 0; i < Keys.length; i++) {
K[Keys[i]] = [];
}
for (i = 0; i < Modifiers.length; i++) {
M[Modifiers[i]] = [];
}
};
Hp12c_dispatcher.init_vars();
I = 11;
K[I][H.FF] = H.make_closure("amortization", [], "AMORT");
K[I][H.GG] = H.make_closure("ston_12x", [], "n 12x");
K[I][H.GG].dont_rst_do_fincalc = 1;
K[I][H.RCL] = H.make_closure("rclfin", [0], "RCL n");
K[I][H.RCL_GG] = H.make_closure("rclfin", [0, 1], "RCL 12x n");
K[I][H.STO] = H.make_closure("stofin", [0], "STO n");
K[I][H.STO].dont_rst_do_fincalc = 1;
K[I][0] = H.make_closure("sto_or_calc_fin", [0], "n");
K[I][0].dont_rst_do_fincalc = 1;
I = 12;
K[I][H.FF] = H.make_closure("simple_interest", [], "INT");
K[I][H.GG] = H.make_closure("stoi_12div", [], "i 12/");
K[I][H.GG].dont_rst_do_fincalc = 1;
K[I][H.RCL] = H.make_closure("rclfin", [1], "RCL i");
K[I][H.RCL_GG] = H.make_closure("rclfin", [1, 1], "RCL 12/ i");
K[I][H.STO] = H.make_closure("stofin", [1], "STO i");
K[I][H.STO].dont_rst_do_fincalc = 1;
K[I][0] = H.make_closure("sto_or_calc_fin", [1], "i");
K[I][0].dont_rst_do_fincalc = 1;
I = 13;
K[I][H.FF] = H.make_closure("npv", [], "NPV");
K[I][H.GG] = H.make_closure("stoCF0", [], "CF0");
K[I][H.RCL] = H.make_closure("rclfin", [2], "RCL PV");
K[I][H.STO] = H.make_closure("stofin", [2], "STO PV");
K[I][H.STO].dont_rst_do_fincalc = 1;
K[I][0] = H.make_closure("sto_or_calc_fin", [2], "PV");
K[I][0].dont_rst_do_fincalc = 1;
I = 14;
K[I][H.FF] = H.make_closure("rnd", [], "RND");
K[I][H.GG] = H.make_closure("stoCFj", [], "CFj");
K[I][H.RCL] = H.make_closure("rclfin", [3], "RCL PMT");
K[I][H.RCL_GG] = H.make_closure("rclCFj", [], "RCL CFj");
K[I][H.STO] = H.make_closure("stofin", [3], "STO PMT");
K[I][H.STO].dont_rst_do_fincalc = 1;
K[I][0] = H.make_closure("sto_or_calc_fin", [3], "PMT");
K[I][0].dont_rst_do_fincalc = 1;
I = 15;
K[I][H.FF] = H.make_closure("irr", [], "IRR");
K[I][H.GG] = H.make_closure("stoNj", [], "Nj");
K[I][H.RCL_GG] = H.make_closure("rclNj", [], "RCL Nj");
K[I][H.RCL] = H.make_closure("rclfin", [4], "RCL FV");
K[I][H.STO] = H.make_closure("stofin", [4], "STO FV");
K[I][H.STO].dont_rst_do_fincalc = 1;
K[I][0] = H.make_closure("sto_or_calc_fin", [4], "FV");
K[I][0].dont_rst_do_fincalc = 1;
I = 16;
if (H.type == "12c-platinum") {
K[I][H.FF] = H.make_closure("rpn_mode", [], "RPN");
} else if (H.type === "12c-bs") {
K[I][H.FF] = H.make_closure("bs_rho", [], "BS RHO");
}
K[I][H.GG] = H.make_closure("date_date", [], "DATE");
K[I][0] = H.make_closure("chs", [], "CHS");
for (I = 0; I <= 9; ++I) {
var SI = I.toString(16);
// adds all functions that are commond to all digits
K[I][H.FF] = H.make_closure("set_decimals", [I, H.NOTATION_FIX], "FIX " + SI);
K[I][H.RCL] = H.make_closure("rcl", [I], "RCL " + SI);
K[I][H.RCL2] = H.make_closure("rcl", [I + 10], "RCL . " + SI);
K[I][H.STO] = H.make_closure("sto", [I], "STO " + SI);
K[I][H.STO2] = H.make_closure("sto", [I + 10], "STO . " + SI);
K[I][H.STO_PLUS] = H.make_closure("stoinfix", [I, H.STO_PLUS], "STO + " + SI);
K[I][H.STO_MINUS] = H.make_closure("stoinfix", [I, H.STO_MINUS], "STO - " + SI);
K[I][H.STO_TIMES] = H.make_closure("stoinfix", [I, H.STO_TIMES], "STO x " + SI);
K[I][H.STO_DIVIDE] = H.make_closure("stoinfix", [I, H.STO_DIVIDE], "STO / " + SI);
K[I][H.GTO] = H.make_closure("gto_digit_add", [I], "GTO DIGIT ADD " + I);
K[I][H.GTO].dont_rst_modifier = 1;
K[I][0] = H.make_closure("digit_add", [I], "" + SI);
}
I = 7;
K[I][H.GG] = H.make_closure("set_begin", [1], "BEGIN");
K[I][H.GG].dont_rst_do_fincalc = 1;
I = 8;
K[I][H.GG] = H.make_closure("set_begin", [0], "END");
K[I][H.GG].dont_rst_do_fincalc = 1;
I = 9;
K[I][H.GG] = H.make_closure("mem_info", [], "MEM");
K[I][H.GG].no_pgrm = 1;
I = 10;
K[I][0] = H.make_closure("divide", [], "/");
M[I][H.STO] = H.STO_DIVIDE;
if (H.type == "12c-platinum") {
K[I][H.GG] = H.make_closure("platinum_undo", [], "UNDO");
} else if (H.type === "12c-bs") {
K[I][H.FF] = H.make_closure("bs_252div", [], "n 252/");
K[I][H.GG] = H.make_closure("bs_365div", [], "n 365/");
}
I = 21;
if (H.type === "12c-bs") {
K[I][H.FF] = H.make_closure("bs_premium", [], "BS PREMIUM");
} else {
K[I][H.FF] = H.make_closure("bond_price", [], "PRICE");
}
K[I][H.GG] = H.make_closure("sqroot", [], "SQRT");
K[I][0] = H.make_closure("poweryx", [], "POWER");
I = 22;
if (H.type === "12c-bs") {
K[I][H.FF] = H.make_closure("bs_theta", [], "BS THETA");
} else {
K[I][H.FF] = H.make_closure("bond_yield", [], "YTM");
}
K[I][H.GG] = H.make_closure("exp", [], "EXP");
K[I][0] = H.make_closure("reciprocal", [], "1/X");
I = 23;
if (H.type === "12c-bs") {
K[I][H.FF] = H.make_closure("bs_gamma", [], "BS GAMMA");
K[I][H.RCL_GG] = H.make_closure("ln_imag", [], "LN IMAG");
} else {
K[I][H.FF] = H.make_closure("depreciation_sl", [], "DEPR SL");
}
K[I][H.GG] = H.make_closure("ln", [], "LN");
K[I][0] = H.make_closure("percentT", [], "%T");
I = 24;
if (H.type === "12c-bs") {
K[I][H.FF] = H.make_closure("bs_delta", [], "BS DELTA");
} else {
K[I][H.FF] = H.make_closure("depreciation_soyd", [], "DEPR SOYD");
}
K[I][H.GG] = H.make_closure("frac", [], "FRAC");
K[I][0] = H.make_closure("deltapercent", [], "D%");
I = 25;
if (H.type === "12c-bs") {
K[I][H.FF] = H.make_closure("bs_vega", [], "BS VEGA");
} else {
K[I][H.FF] = H.make_closure("depreciation_db", [], "DEPR DB");
}
K[I][H.GG] = H.make_closure("intg", [], "INTG");
K[I][0] = H.make_closure("percent", [], "%");
I = 26;
if (H.type === "12c-bs") {
K[I][H.FF] = H.make_closure("bs_dys252", [], "DYS252");
}
K[I][H.GG] = H.make_closure("date_dys", [], "DYS");
K[I][H.STO] = H.make_closure("toggle_compoundf", [], "STOEEX");
K[I][0] = H.make_closure("input_exponential", [], "EEX");
if (H.type == "12c-platinum") {
K[I][H.FF] = H.make_closure("algebraic_mode", [], "ALG");
}
I = 4;
K[I][H.GG] = H.make_closure("set_dmy", [1], "D.MY");
I = 5;
K[I][H.GG] = H.make_closure("set_dmy", [0], "M.DY");
I = 6;
K[I][H.GG] = H.make_closure("stat_avgw", [], "STAT AVGW");
I = 20;
if (H.type == "12c-platinum") {
K[I][H.GG] = H.make_closure("square", [], "SQUARE");
} else if (H.type === "12c-bs") {
K[I][H.FF] = H.make_closure("bs_d1", [], "BS d1");
K[I][H.GG] = H.make_closure("bs_d2", [], "BS d2");
}
K[I][0] = H.make_closure("multiply", [], "x");
M[I][H.STO] = H.STO_TIMES;
I = 31;
K[I][H.GG] = H.make_closure("pse", [], "PSE");
K[I][H.FF] = H.make_closure("prog_pr", [], "P/R");
K[I][0] = H.make_pgrm_closure("rs", [], "R/S");
I = 32;
K[I][H.FF] = H.make_closure("clear_statistics", [], "CLEAR STAT");
K[I][H.GG] = H.make_pgrm_closure("bst", [], "BST");
K[I][0] = H.make_pgrm_closure("sst", [], "SST");
I = 33;
K[I][H.FF] = H.make_closure("clear_prog", [0], "CLEAR PROG");
K[I][0] = H.make_closure("r_down", [], "Rv");
M[I][H.GG] = H.GTO;
I = 34;
K[I][H.FF] = H.make_closure("clear_fin", [], "CLEAR FIN");
K[I][H.GG] = H.make_closure("test_x_le_y", [], "x<=y");
K[I][0] = H.make_closure("x_exchange_y", [], "X<->Y");
I = 35;
K[I][H.FF] = H.make_closure("clear_reg", [], "CLEAR REG");
K[I][H.GG] = H.make_closure("test_x_eq0", [], "x=0");
K[I][0] = H.make_closure("clx", [], "CLx");
I = 36;
K[I][H.FF] = H.make_closure("clear_prefix", [], "CLEAR PREFIX");
K[I][H.FF].no_pgrm = 1;
if (H.type == "12c-platinum") {
K[I][H.GG] = H.make_closure("enter", [1], "g ENTER");
} else {
K[I][H.GG] = H.make_closure("lstx", [], "LSTx");
}
K[I][0] = H.make_closure("enter", [0], "ENTER");
I = 1;
K[I][H.GG] = H.make_closure("stat_lr", [1], "STAT LR X");
I = 2;
K[I][H.GG] = H.make_closure("stat_lr", [0], "STAT LR Y");
I = 3;
K[I][H.GG] = H.make_closure("fatorial", [], "n!");
I = 30;
K[I][0] = H.make_closure("minus", [], "-");
K[I][H.GG] = H.make_closure("digit_delete", [], "BSP PLATINUM");
K[I][H.GG].no_pgrm = 1;
if (H.type === "12c-bs") {
K[I][H.FF] = H.make_closure("bs_normal", [], "BS NORMAL");
}
M[I][H.STO] = H.STO_MINUS;
I = 41;
K[I][0] = H.make_closure("toggle_decimal_character", [], "ON");
K[I][0].no_pgrm = 1;
K[I][H.RCL] = H.make_closure("shv", [], "SHV");
K[I][H.RCL].no_pgrm = 1;
K[I][H.RCL_GG] = H.make_closure("test_offsets", [], "TEST OFFSETS");
K[I][H.RCL_GG].no_pgrm = 1;
K[I][H.STO] = H.make_closure("apocryphal", [1], "APOCRYPHAL 1");
K[I][H.STO].no_pgrm = 1;
I = 42;
M[I][0] = H.FF;
I = 43;
M[I][0] = H.GG;
M[I][H.RCL] = H.RCL_GG;
I = 44;
M[I][0] = H.STO;
if (H.type == "12c-platinum") {
K[I][H.GG] = H.make_closure("algebraic_open_parentheses", [], "(");
}
I = 45;
M[I][0] = H.RCL;
if (H.type == "12c-platinum") {
K[I][H.GG] = H.make_closure("algebraic_close_parentheses", [], ")");
}
I = 0;
K[I][H.GG] = H.make_closure("stat_avg", [], "STAT AVG");
I = 48;
K[I][H.FF] = H.make_closure("set_decimals_exponential", [], "FIX .");
K[I][H.GG] = H.make_closure("stat_stddev", [], "STAT STDDEV");
K[I][H.GTO] = H.make_closure("gto_buf_clear", [], "GTO BUF CLR");
K[I][0] = H.make_closure("decimal_point_mode", [], ".");
M[I][H.STO] = H.STO2;
M[I][H.RCL] = H.RCL2;
I = 49;
K[I][H.GG] = H.make_closure("stat_sigma_minus", [], "STAT S-");
K[I][0] = H.make_closure("stat_sigma_plus", [], "STAT S+");
if (H.type === "12c-bs") {
K[I][H.FF] = H.make_closure("bs_implvolC", [], "BS IMPL C");
}
I = 40;
if (H.type == "12c-platinum") {
K[I][H.GG] = H.make_closure("lstx", [], "LSTx");
} else if (H.type === "12c-bs") {
K[I][H.FF] = H.make_closure("bs_implvolP", [], "BS IMPL P");
K[I][H.GG] = H.make_closure("bs_cumul", [], "BS CUMUL");
}
K[I][0] = H.make_closure("plus", [], "+");
M[I][H.STO] = H.STO_PLUS;
K[I][H.RCL_GG] = H.make_closure("toggle_feedback", [], "TOGGLE FEEDBACK");
K[I][H.RCL_GG].no_pgrm = 1;
I = 98;
K[I][0] = H.make_closure("digit_delete", [], "BSP");
K[I][0].no_pgrm = 1;
Hp12c_dispatcher.prototype.handle_modifier = function (key, pgrm_mode)
{
var self = this;
var modifier_table = self.modifier_sm[key];
var f = self.find_function(key, 0, 1);
if (modifier_table) {
var next_modifier = modifier_table[H.machine.modifier];
if (next_modifier) {
// a modifier potentialized by a previous one
H.machine.set_modifier(next_modifier);
return true;
} else if (modifier_table[0] && !f) {
// a modifier of its own right, like f, g
H.machine.set_modifier(modifier_table[0]);
return true;
}
}
return false;
};
Hp12c_dispatcher.prototype.find_function = function (key, pgrm_mode, query)
{
var self = this;
var function_table = self.functions[key];
var f = null;
if (function_table) {
f = function_table[H.machine.modifier];
if (!f) {
// no function given current modifier
f = function_table[0];
if (f && ! query) {
// function without modifier
H.machine.rst_modifier(1);
}
}
}
if (pgrm_mode && f && f.no_pgrm) {
// this function can not be programmed; revoked
f = null;
}
return f;
};
Hp12c_dispatcher.prototype.dispatch = function (key)
{
var self = this;
if (self.dispatch_basic(key)) {
return;
} else if (H.machine.program_mode == H.PROGRAMMING) {
H.pgrm.type(key);
return;
}
self.dispatch_common(key);
};
Hp12c_dispatcher.prototype.dispatch_common = function (key)
{
var self = this;
// this is used both by real keys and program scheduler
var ok = 1;
if (self.handle_modifier(key, 0)) {
return ok;
}
// key is not modifier in this context, try a function
var f = self.find_function(key, 0, 0);
if (!f) {
f = function () {
// no-op
};
ok = false;
}
var rst_modifier = 1;
var rst_do_fincalc = 1;
if (f.dont_rst_do_fincalc) {
rst_do_fincalc = 0;
}
if (f.dont_rst_modifier) {
rst_modifier = 0;
}
f();
if (rst_modifier) {
H.machine.rst_modifier(rst_do_fincalc);
}
return ok;
};
// remove from scope
M = undefined;
K = undefined;
I = undefined;
H.asm_reverse_map = null;
H.asm_ucode_reverse_map = null;
H.asm_make_reverse_map = function ()
{
var map = {};
var umap = {};
H.asm_reverse_map = map;
H.asm_ucode_reverse_map = umap;
var K = Hp12c_dispatcher.prototype.functions;
// pure modifier keys, with no K[key][0]
umap.FF = 42;
umap.STO = 44;
umap.RCL = 45;
if (H.type === "16c") {
umap.GG = 43;
umap.GSB = 21;
umap.LBL = 22;
umap.GTO = 22;
} else if (H.type === "10c") {
umap.GTO = 22;
} else if (H.type === "11c" || H.type === "15c") {
umap.GG = 43;
umap.GTO = 22;
umap.GSB = 32;
umap.LBL = 21;
umap.DIM = 23;
umap.MATRIX = 16;
umap.A = 11;
umap.B = 12;
umap.C = 13;
umap.D = 14;
umap.E = 15;
} else { // 12c
umap.GG = 43;
umap.GTO = 33;
}
for (var key in K) {
if (K.hasOwnProperty(key)) {
for (var modifier in K[key]) {
if (K[key].hasOwnProperty(modifier)) {
var closure = K[key][modifier];
if (! closure.asm) {
continue;
}
var imodifier = modifier;
var ikey = key;
if (closure.reducible) {
if (imodifier >= 10000) {
// 11C, 15C: this key sequence cannot
// be translated to an opcode, since it
// is reduced before goes to RAM
continue;
}
}
var is_addr = false;
var mnemonic = closure.asm.toUpperCase();
var opcode = Hp12c_pgrm.p_encode_instruction(parseInt(imodifier, 10),
parseInt(ikey, 10),
is_addr);
if (map[mnemonic]) {
throw "Mnemonic already exists: " + mnemonic +
" existing code " + map[mnemonic] + " " +
" other code " + opcode;
}
map[mnemonic] = opcode;
// iterating over K yields string keys
umap[mnemonic] = parseInt(key, 10);
}
}
}
}
window.xlog("Making asm done");
};
H.asm_condition = function (s)
{
s = H.trim(s).toUpperCase();
return s.replace(/\s{2,}/g, ' ');
};
H.asm_gto12 = function (s)
{
var regex_gto12 = new RegExp('^GTO [0-9]+$');
if (! regex_gto12.test(s)) {
return null;
}
var ip = 0 + s.substr(4);
if (ip >= H.ram_MAX) {
window.xlog("IP too high: " + s);
return null;
}
// TODO 4333 should come from dispatch
return Hp12c_pgrm.p_encode_instruction(parseInt(4333, 10),
parseInt(ip, 10),
true);
};
H.asm_gto10 = function (s)
{
var regex_gto10 = new RegExp('^GTO [0-9]+$');
if (! regex_gto10.test(s)) {
return null;
}
var ip = 0 + s.substr(4);
if (ip >= H.ram_MAX) {
window.xlog("IP too high: " + s);
return null;
}
// TODO 22 should come from dispatch
return Hp12c_pgrm.p_encode_instruction(parseInt(22, 10),
parseInt(ip, 10),
true);
};
H.asm = function (instr, query)
{
if (! H.asm_reverse_map) {
H.asm_make_reverse_map();
}
var map = H.asm_reverse_map;
var c12 = H.is_12c();
var c10 = H.type === "10c";
instr = H.asm_condition(instr);
var opcode = null;
if (map[instr]) {
opcode = map[instr];
} else if (c12 && H.asm_gto12(instr)) {
opcode = H.asm_gto12(instr);
} else if (c10 && H.asm_gto10(instr)) {
opcode = H.asm_gto10(instr);
} else {
if (! query) {
throw "asm: Invalid instruction: " + instr;
}
}
return opcode;
};
H.asm_microcode = function (ucodename, query)
{
if (! H.asm_reverse_map) {
H.asm_make_reverse_map();
}
ucodename = H.asm_condition(ucodename);
if (H.asm_ucode_reverse_map[ucodename] === undefined ||
H.asm_ucode_reverse_map[ucodename] === null) {
if (! query) {
throw ">>>> Invalid microcode " + ucodename;
}
return null;
}
return H.asm_ucode_reverse_map[ucodename];
};
H.asm_expand = function (progr)
{
var result = [];
var regex_number = new RegExp('^[0-9.]+$');
for (var i = 0; i < progr.length; ++i) {
var instr = progr[i];
if (H.asm(instr, true)) {
result.push(instr);
} else if (regex_number.test(instr)) {
for (var j = 0; j < instr.length; ++j) {
result.push(instr.charAt(j));
}
} else {
result.push(instr);
}
}
return result;
};
H.asm_microcode_expand = function (progr)
{
var result = [];
var regex_number = new RegExp('^[0-9.]+$');
for (var i = 0; i < progr.length; ++i) {
var instr = progr[i];
if (instr === null) {
// skip
} else if (H.asm_microcode(instr, true)) {
result.push(instr);
} else if (regex_number.test(instr)) {
for (var j = 0; j < instr.length; ++j) {
result.push(instr.charAt(j));
}
} else {
result.push(instr);
}
}
return result;
};
H.asm_compile = function (progr, base_addr)
{
progr = H.asm_expand(progr);
for (var i = 0; i < progr.length; ++i) {
H.machine.ram[base_addr + i + 1] = H.asm(progr[i]);
}
return progr.length;
};
H.asm_microcode_exec = function (microcode, monitor)
{
for (var i = 0; i < microcode.length; ++i) {
window.xlog("> Typed " + microcode[i]);
H.dispatcher.dispatch(microcode[i]);
if (monitor) {
monitor(i);
}
}
};
/*
Assembly = whole instructions
Microcode = actual keystrokes
Example:
"STO 0" is an assembly instruction
It compiles to opcode "44.00"
Microcode/keystrokes would be [44, 00].
Microcode is useful to simulate program typing, among
other things.
*/
H.asm_microcode_compile = function (microprogram)
{
microprogram = H.asm_microcode_expand(microprogram);
var microcode = [];
for (var i = 0; i < microprogram.length; ++i) {
microcode[i] = H.asm_microcode(microprogram[i]);
}
return microcode;
};
/*jshint white: true, undef: true, nomen: true, regexp: true, strict: true, browser: true, bitwise: false */
/*jshint globalstrict: true*/
/*global H */
"use strict";
H.INTERPOLATION_MAX = 100;
H.THRESHOLD_TENDIGITS = 0.000000001;
H.THRESHOLD_ELEVENDIGITS = 0.0000000001;
H.THRESHOLD_TWELVEDIGITS = 0.00000000001;
H.solve_infinity = function (val)
{
if (val > 1e95) {
val = 1e95;
} else if (val < -1e95) {
val = -1e95;
}
return val;
};
// better pow() for bases in the form 1 + i when i is small
// base is actually (1 + base_m1)
H.finance_pow = function (base_m1, exponent)
{
if (Math.abs(base_m1) > 0.000001) {
return Math.pow(1 + base_m1, exponent);
}
// pow(b, e) = exp(e * ln(b))
// use the fact ln(1+x) ~= x for x very near 1
// pow(B + 1, e) = exp(e * B)
// use a small Taylor series
// idea from http://colorfulengineering.org/logmath-notes.pdf
// In the future, when all Javascript engines support log1p(),
// we can replace this by log1p()
var log_m1 = (-0.5 * base_m1 + 1.0) * base_m1;
return Math.exp(exponent * log_m1);
};
H.npv = function (n, i, cfj, nj)
{
var threshold = H.npv_threshold_ten(n, cfj);
var res = H._npv(n, i, cfj, nj);
if (Math.abs(res) < threshold) {
res = 0;
}
return res;
};
H._npv = function (n, i, cfj, nj)
{
var res = cfj[0];
var pmt = 0;
for (var e = 1; e <= n; ++e) {
var cf = cfj[e];
for (var f = 1; f <= nj[e]; ++f) {
++pmt;
res += cf / H.finance_pow(i / 100, pmt);
}
}
return res;
};
H.npv_quality = function (n, cfj, nj)
{
var sgn = 0;
if (cfj[0] > 0) {
sgn = 1;
} else if (cfj[0] < 0) {
sgn = -1;
}
for (var e = 1; e <= n; ++e) {
if (nj[e] !== 0) {
var newsgn = 0;
if (cfj[e] > 0) {
newsgn = 1;
} else if (cfj[e] < 0) {
newsgn = -1;
}
if (newsgn !== 0) {
if (sgn !== 0) {
if (newsgn !== sgn) {
// signal inversion, exit with sucess
return +1;
}
}
sgn = newsgn;
}
}
}
// no signal inversions, or all-zeros
return (sgn === 0) ? 0 : -1;
};
H.comppmtlim = function (i, n)
{
if (Math.abs(i) < H.THRESHOLD_ELEVENDIGITS) {
return n;
} else {
return (1 - H.finance_pow(i / 100, -n)) / (i / 100);
}
};
H.calcNPV = function (is_n, n, i, pv, pmt, fv, begin, compoundf)
{
if (n == Math.floor(n) || is_n) {
return pv +
(1 + (i / 100) * (begin ? 1:0)) * pmt * H.comppmtlim(i, n) +
fv * H.finance_pow(i / 100, -n);
} else if (! compoundf) {
return pv * (1 + ((i / 100) * (n - Math.floor(n)))) +
(1 + (i / 100) * (begin ? 1:0)) * pmt * H.comppmtlim(i, Math.floor(n)) +
fv * H.finance_pow(i / 100, -Math.floor(n));
} else {
return pv * H.finance_pow(i / 100, (n - Math.floor(n))) +
(1 + (i / 100) * (begin ? 1 : 0)) * pmt * H.comppmtlim(i, Math.floor(n)) +
fv * H.finance_pow(i / 100, -Math.floor(n));
}
};
H.bond_previous_coupon = function (buy, maturity)
{
// calculates last coupon paid just before buy
var coupons = 0;
var last_coupon = new Date(maturity);
var next_coupon;
while (last_coupon > buy) {
next_coupon = new Date(last_coupon);
++coupons;
last_coupon.setDate(1);
last_coupon.setMonth(last_coupon.getMonth() - 6);
var month = last_coupon.getMonth();
last_coupon.setDate(maturity.getDate());
if (last_coupon.getMonth() != month) {
// day > 28, overflowed into next month
// Javascript trick: set to day 0 goes to last day of previous month
// last_coupon.setDate(0);
// We *could* do this calculation, but HP-12C returns Error 8 in this case,
// so do we
return null;
}
}
return [last_coupon, next_coupon, coupons];
};
H.bond_price = function (desired_rate, coupon_year, buy, maturity)
{
var price;
var tot_interest;
// * HP-12C only calculates semi-annual bonds i.e. bonds which pay coupons every 6 mo
// * Value paid at maturity is always = 100
// desire rate is pre-checked to be > -100
var coupon_date = maturity;
var tottime = H.date_diff(buy, maturity);
if (tottime <= 0) {
return [H.ERROR_DATE, 0, 0];
}
var res = H.bond_previous_coupon(buy, maturity);
if (res === null) {
return [H.ERROR_DATE, 0, 0];
}
var E = H.date_diff(res[0], res[1]);
var dsc = H.date_diff(buy, res[1]); // time between settlement (buying) and next coupon
var coupons = res[2]; // coupons that will be paid until maturity
var dcs = E - dsc; // time since last coupon, paid before we bought it.
if (tottime <= E) {
price = (100 * (100 + coupon_year / 2)) / (100 + ((tottime / E) * desired_rate / 2)); // present-value price
} else {
price = 100 / H.finance_pow(desired_rate / 200, coupons - 1 + dsc / E); // present-value price
for (var e = 1; e <= coupons; ++e) {
// accumulate present value of all future coupons
price += (coupon_year / 2) / H.finance_pow(desired_rate / 200, e - 1 + dsc / E);
}
}
tot_interest = (coupon_year / 2) * dcs / E;
price -= tot_interest; // coupon fraction compound before we bought it
// should never happen, since previous checkings avoid NaN cases
price = H.solve_infinity(price) || 0;
tot_interest = H.solve_infinity(tot_interest) || 0;
return [-1, price, tot_interest];
};
H.npv_threshold_ten = function (n, cfj)
{
var threshold = H.THRESHOLD_TENDIGITS;
var magnitude = Math.abs(cfj[0]);
for (var e = 1; e <= n; ++e) {
magnitude += Math.abs(cfj[e]);
}
if (magnitude > 0) {
threshold *= magnitude;
}
return threshold;
};
H.irr_calc = function (n, i, cfj, nj)
{
var quality = H.npv_quality(n, cfj, nj);
if (quality === 0) {
// all-zeros
return [-1, 0];
} else if (quality < 0) {
// all data have the same signal
return [H.ERROR_IRR, i];
}
var NPVA, NPVL, NPVH, guessL, guessH;
// 12-digit threshold
var threshold = H.npv_threshold_ten(n, cfj) / 100;
if (i <= -98 || i > 10000000000) {
i = 0;
}
guessL = i - 1;
guessH = i + 1;
var success = false;
// find an interval guessL..guessH that contains NPV = 0
var iteration = H.INTERPOLATION_MAX;
while (--iteration >= 0) {
// window.xlog("Trying interval " + guessL + " " + guessH);
NPVH = H._npv(n, guessH, cfj, nj);
NPVL = H._npv(n, guessL, cfj, nj);
// success condition
if ((NPVH * NPVL) < 0) {
success = true;
break;
}
var diff = guessH - guessL;
if (guessL < 0) {
guessL = Math.max(-99.99999999, guessL * 1.5); // counting with 100 iterations
} else {
guessL = Math.max(-99.99999999, guessL - 5 * diff); // counting with 100 iterations
}
guessH = Math.min(guessH + 5 * diff, 1e99);
}
if (success) {
// Now bisect to find NPV(guess) = 0
iteration = H.INTERPOLATION_MAX;
while (--iteration >= 0) {
// window.xlog("Trying bisection " + guessL + " " + guessH);
var avg = (guessL + guessH) / 2;
NPVA = H._npv(n, avg, cfj, nj);
if (Math.abs(NPVA) < threshold) {
return [-1, avg];
}
if ((NPVL * NPVA) < 0) {
// zero between L and avg
NPVH = NPVA;
guessH = avg;
} else {
// zero between avg and H
NPVL = NPVA;
guessL = avg;
}
// window.xlog("Interval NPV is " + NPVL + " " + NPVH);
}
}
return [H.ERROR_IRR2, i];
};
H.financecalc = function (dependent, begin, compoundf, finarray)
{
var err = 0;
if (dependent === 0) {
// n
var tpmt = finarray[H.FIN_PMT];
var tpvi = -finarray[H.FIN_PV] * finarray[H.FIN_I] / 100;
var tfvi = finarray[H.FIN_FV] * finarray[H.FIN_I] / 100;
var tfv = finarray[H.FIN_FV];
if (tpmt < 0) {
tpmt = -tpmt;
tpvi = -tpvi;
tfvi = -tfvi;
tfv = -tfv;
}
err = err || finarray[H.FIN_I] <= -100; // i <= -100
// "if" is kludge to work around a problem with PMT = 0 and FV != 0
if (tfv === 0) {
err = err || (tpmt <= tpvi); // PMT <= -VP x i
err = err || H.feq10(tpmt, tpvi); // PMT <= -VP x i
}
// I am in doubt in relation to signal
// err = err || H.feq10(tpmt, tfvi); // PMT == VF x i
} else if (dependent == 1) {
var pmtn = finarray[H.FIN_PMT] * finarray[H.FIN_N];
err = err || (finarray[H.FIN_N] < 0);
err = err || (pmtn >= 0 && finarray[H.FIN_PV] >= 0 && finarray[H.FIN_FV] >= 0);
err = err || (pmtn <= 0 && finarray[H.FIN_PV] <= 0 && finarray[H.FIN_FV] <= 0);
} else if (dependent == 2) {
// PV
err = err || finarray[H.FIN_I] <= -100; // i <= -100
} else if (dependent == 3) {
// PMT
err = err || finarray[H.FIN_I] <= -100; // i <= -100
err = err || finarray[H.FIN_N] === 0; // n = 0
} else if (dependent == 4) {
// FV
err = err || finarray[H.FIN_I] <= -100; // i <= -100
}
if (err) {
return H.ERROR_INTEREST;
}
var threshold = H.THRESHOLD_TWELVEDIGITS;
var threshold_magnitude = 0;
var threshold_result = H.THRESHOLD_TENDIGITS;
var threshold_result_magnitude = 0;
// correct threshold so it is proportional to the numbers involved
if (dependent != H.FIN_PV) {
threshold_magnitude += Math.abs(finarray[H.FIN_PV]);
threshold_result_magnitude += Math.abs(finarray[H.FIN_PV]);
}
if (dependent != H.FIN_PMT) {
threshold_magnitude += Math.abs(finarray[H.FIN_PMT]);
threshold_result_magnitude += Math.abs(finarray[H.FIN_PMT]);
}
if (dependent != H.FIN_N && dependent != H.FIN_PMT) {
// reduce calc precision because big N might make it impossible to
// find a result if too picky
threshold_magnitude += Math.abs(finarray[H.FIN_N] * finarray[H.FIN_PMT]);
}
if (dependent != H.FIN_FV) {
threshold_magnitude += Math.abs(finarray[H.FIN_FV]);
threshold_result_magnitude += Math.abs(finarray[H.FIN_FV]);
}
if (threshold_magnitude > 0) {
threshold *= threshold_magnitude;
}
if (threshold_result_magnitude > 0) {
threshold_result *= threshold_result_magnitude;
}
if (dependent === 1) {
return H.financecalc_i(dependent, begin, compoundf, finarray, threshold, threshold_magnitude);
}
var guess0, guess1, NPV0, NPV1;
var saved = finarray[dependent];
var iteration = H.INTERPOLATION_MAX;
guess0 = null;
if (dependent == H.FIN_N || dependent == H.FIN_I || threshold_magnitude <= 0) {
guess1 = 1;
} else {
// initial guess for interpolation must be of same magnitude as other parameters
guess1 = threshold_magnitude;
}
var ret = H.ERROR_INTEREST;
while (--iteration >= 0) {
finarray[dependent] = guess1;
NPV1 = H.calcNPV(dependent === 0,
finarray[H.FIN_N], finarray[H.FIN_I], finarray[H.FIN_PV],
finarray[H.FIN_PMT], finarray[H.FIN_FV], begin, compoundf);
if (Math.abs(NPV1) < threshold) {
if (dependent === 0) {
if ((guess1 - Math.floor(guess1)) > 0.003) {
finarray[dependent] = Math.floor(finarray[dependent]) + 1;
} else {
finarray[dependent] = Math.floor(finarray[dependent]);
}
} else {
// handle insignificant residues for PV, PMT and FV
if (Math.abs(finarray[dependent]) < threshold_result) {
finarray[dependent] = 0;
}
}
saved = finarray[dependent];
ret = -1;
break;
}
var new_guess = guess1 + 1;
if (guess0 !== null) {
var B = (NPV1 - NPV0) / (guess1 - guess0); // B
new_guess = NPV0 - guess0 * B; // A
new_guess /= -B; // -A/B is the interpolation root
new_guess = H.solve_infinity(new_guess);
}
guess0 = guess1;
NPV0 = NPV1;
guess1 = new_guess;
NPV1 = null;
}
// puts back the original value in case of error,
// since the calculated one may be NaN
finarray[dependent] = saved;
return ret;
};
// separate routine since linear interpolation does not work well for i
H.financecalc_i = function (dependent, begin, compoundf, finarray, threshold, threshold_magnitude)
{
var NPVA, NPVL, NPVH, guessL, guessH;
var saved = finarray[dependent];
var ret = H.ERROR_INTEREST;
var success = false;
guessL = -1;
guessH = +1;
// find an interval guessL..guessH that contains NPV = 0
var iteration = H.INTERPOLATION_MAX;
while (--iteration >= 0) {
// window.xlog("Trying interval " + guessL + " " + guessH);
finarray[dependent] = guessH;
NPVH = H.calcNPV(dependent === 0,
finarray[H.FIN_N], finarray[H.FIN_I], finarray[H.FIN_PV],
finarray[H.FIN_PMT], finarray[H.FIN_FV], begin, compoundf);
finarray[dependent] = guessL;
NPVL = H.calcNPV(dependent === 0,
finarray[H.FIN_N], finarray[H.FIN_I], finarray[H.FIN_PV],
finarray[H.FIN_PMT], finarray[H.FIN_FV], begin, compoundf);
// window.xlog("Interval NPV is " + NPVL + " " + NPVH);
// success condition
if ((NPVH * NPVL) < 0) {
success = true;
break;
}
guessL = Math.max(-99.99999999, guessL - 1.1); // counting with 100 iterations
guessH = Math.min(guessH * 10, 1e99);
}
if (success) {
// Now bisect to find NPV(guess) = 0
iteration = H.INTERPOLATION_MAX;
while (--iteration >= 0) {
// window.xlog("Trying bisection " + guessL + " " + guessH);
var avg = (guessL + guessH) / 2;
finarray[dependent] = avg;
NPVA = H.calcNPV(dependent === 0,
finarray[H.FIN_N], finarray[H.FIN_I], finarray[H.FIN_PV],
finarray[H.FIN_PMT], finarray[H.FIN_FV], begin, compoundf);
if (Math.abs(NPVA) < threshold) {
return -1;
}
if ((NPVL * NPVA) < 0) {
// zero between L and avg
NPVH = NPVA;
guessH = avg;
} else {
// zero between avg and H
NPVL = NPVA;
guessL = avg;
}
// window.xlog("Interval NPV is " + NPVL + " " + NPVH);
}
}
finarray[dependent] = saved;
return ret;
};
H.bond_yield = function (coupon_year, buy, maturity, price)
{
if (buy === null) {
return [H.ERROR_DATE, 0];
}
if (maturity === null) {
return [H.ERROR_DATE, 0];
}
if (price <= 0) {
return [H.ERROR_INTEREST, 0];
}
var NPVA, NPVL, NPVH, guessL, guessH;
var threshold = H.THRESHOLD_ELEVENDIGITS * Math.abs(price);
guessL = -1;
guessH = +1;
var success = false;
var err = H.ERROR_INTEREST;
// find an interval guessL..guessH that contains NPV = 0
var iteration = H.INTERPOLATION_MAX;
while (--iteration >= 0) {
// window.xlog("Trying interval " + guessL + " " + guessH);
NPVL = H.bond_price(guessL, coupon_year, buy, maturity);
if (NPVL[0] >= 0) {
err = NPVL[0];
break;
}
NPVL = NPVL[1] - price;
NPVH = H.bond_price(guessH, coupon_year, buy, maturity);
/*
Impossible, because all possible errors are related to date and
are caught in NPVL calculation.
if (NPVH[0] >= 0) {
err = NPVH[0];
break;
}
*/
NPVH = NPVH[1] - price;
// success condition
if ((NPVH * NPVL) < 0) {
success = true;
break;
}
guessL = Math.max(-199.99999999, guessL * 1.5); // counting with 100 iterations
guessH = Math.min(guessH * 10, 1e99);
}
if (success) {
// Now bisect to find NPV(guess) = 0
iteration = H.INTERPOLATION_MAX;
while (--iteration >= 0) {
// window.xlog("Trying bisection " + guessL + " " + guessH);
var avg = (guessL + guessH) / 2;
NPVA = H.bond_price(avg, coupon_year, buy, maturity);
/*
Impossible, because all possible errors would have been
caught in previous loop, in NPVL calculation.
if (NPVA[0] >= 0) {
err = NPVA[0];
break;
}
*/
NPVA = NPVA[1] - price;
if (Math.abs(NPVA) < threshold) {
return [-1, avg];
}
if ((NPVL * NPVA) < 0) {
// zero between L and avg
NPVH = NPVA;
guessH = avg;
} else {
// zero between avg and H
NPVL = NPVA;
guessL = avg;
}
// window.xlog("Interval NPV is " + NPVL + " " + NPVH);
}
}
return [err, 0];
};
H.depreciation_sl = function (cost, sell, life, year)
{
var depr = 0;
var rest = cost - sell;
if (year < 0 || year != Math.floor(year) || life <= 0 || life > 1e10) {
return [H.ERROR_INTEREST, 0, 0];
}
if (year > life) {
// bail out early to avoid slowness if year is absurdly big
// linear depreciation does not make sense if year > life
return [-1, 0, 0];
}
while (--year >= 0) {
depr = (cost - sell) / life;
rest -= depr;
}
return [-1, depr, rest];
};
H.depreciation_soyd = function (cost, sell, life, year)
{
var depr = 0;
var rest = cost - sell;
if (year < 0 || year != Math.floor(year) || life <= 0 || life > 1e10) {
return [H.ERROR_INTEREST, 0, 0];
}
if (year > life) {
// bail out early to avoid slowness if year is absurdly big
// soyd depreciation does not make sense if year > life
return [-1, 0, 0];
}
var year_up = 0;
var soyd = life * (life + 1) / 2;
while (--year >= 0) {
depr = (cost - sell) * (life - (++year_up) + 1) / soyd;
rest -= depr;
}
return [-1, depr, rest];
};
H.depreciation_db = function (cost, sell, life, year, db)
{
var depr = 0;
var rest = cost - sell;
if (year < 0 || year != Math.floor(year) || life <= 0 || life > 1e10) {
return [H.ERROR_INTEREST, 0, 0];
}
if (year > life || rest < 0) {
// bail out early to avoid slowness if year is absurdly big
// soyd depreciation does not make sense if year > life
return [-1, 0, 0];
}
var birthday = 0;
while (--year >= 0) {
if (++birthday < life) {
depr = (rest + sell) * db / life;
} else {
depr = rest;
}
rest -= depr;
if (rest < 0) {
// may happen if db is big
depr += rest;
rest = 0;
}
}
return [-1, depr, rest];
};
H.amortization = function (requested_n, orig_n, i, pv, pmt, decimals, begin)
{
if (requested_n <= 0 || requested_n != Math.floor(requested_n) || i <= -1) {
return [H.ERROR_INTEREST, 0, 0];
}
var tot_interest = 0;
var tot_amort = 0;
for (var e = 1; e <= requested_n; ++e) {
var interest = H.cl5_round(-pv * i, decimals);
if (e == 1 && begin && orig_n <= 0) {
// front payment has no interest
interest = 0;
}
var capital_amortization = pmt - interest;
tot_interest += interest;
tot_amort += capital_amortization;
pv += capital_amortization;
}
return [-1, tot_interest, tot_amort];
};
H.degrees_to_radians = function (angle)
{
return angle * Math.PI / 180;
};
H.radians = function (angle, mode) // 11C
{
if (mode == H.TRIGO_DEG) {
angle = H.degrees_to_radians(angle);
} else if (mode == H.TRIGO_GRAD) {
angle *= Math.PI / 200;
}
return angle;
};
H.radians_to_degrees = function (angle)
{
return angle * 180 / Math.PI;
};
H.to_angle_mode = function (angle, mode) // 11C
{
if (mode == H.TRIGO_DEG) {
angle = H.radians_to_degrees(angle);
} else if (mode == H.TRIGO_GRAD) {
angle *= 200 / Math.PI;
}
return angle;
};
H.hour_to_hms = function (hour)
{
var sgn = H.binary_sgn(hour);
var whole_hour = Math.floor(Math.abs(hour));
var fraction = Math.abs(hour) - whole_hour;
fraction *= 60;
// avoid leaving a 0.999... fraction behind
var minutes = Math.floor(fraction + 0.00000001);
// make sure it does not get negative
fraction = Math.max(fraction - minutes, 0);
var seconds = fraction * 60;
return sgn * (whole_hour + minutes / 100 + seconds / 10000);
};
H.hms_to_hour = function (hour)
{
var sgn = H.binary_sgn(hour);
var whole_hour = Math.floor(Math.abs(hour));
var fraction = Math.abs(hour) - whole_hour;
fraction *= 100;
// avoid leaving a 0.999... fraction behind
var minutes = Math.floor(fraction + 0.0000001);
// make sure it does not get negative
fraction = Math.max(fraction - minutes, 0);
var seconds = fraction * 100;
return sgn * (whole_hour + minutes / 60 + seconds / 3600);
};
// hyperbolic functions from http://phpjs.org/functions/
H.asinh = function (arg) {
return Math.log(arg + Math.sqrt(arg * arg + 1));
};
H.acosh = function (arg) {
return Math.log(arg + Math.sqrt(arg * arg - 1));
};
H.atanh = function (arg) {
return 0.5 * Math.log((1 + arg) / (1 - arg));
};
H.sinh = function (arg) {
return (Math.exp(arg) - Math.exp(-arg)) / 2;
};
H.cosh = function (arg) {
return (Math.exp(arg) + Math.exp(-arg)) / 2;
};
H.tanh = function (arg) {
return (Math.exp(arg) - Math.exp(-arg)) / (Math.exp(arg) + Math.exp(-arg));
};
H.feq = function (a, b, epsilon) {
if (a === undefined || a === null || b === undefined || b === null ||
H.badnumber(a) || H.badnumber(b)) {
// window.xlog("feq: bad number");
return false;
}
if (epsilon === undefined || epsilon === null) {
epsilon = 1e-10;
}
/*
// convert numbers into intervals
var A = a - epsilon;
var B = a + epsilon;
var X = b - epsilon;
var Y = b + epsilon;
// interval equality
// return B >= X && A <= Y;
// if numbers are negative, (A,B) (X,Y) will not be in order!
return (A >= X && A <= Y) || (B >= X && B <= Y);
*/
// xlog(" " + a + " " + b + " " + epsilon + " " + Math.abs(a - b) +
// (Math.abs(a - b) < epsilon));
return Math.abs(a - b) <= epsilon;
};
H.arithmetic_round = function (r, a, b)
{
if (r === 0 || r !== r) {
return r;
} else if (a === 0 && b === 0) {
// both zeros, or no rounding desired (mult, div, power)
return r;
}
var magnitude = -999999999;
// pick the magnitude of biggest number
if (a !== 0) {
magnitude = Math.floor(Math.log(Math.abs(a)) / Math.log(10));
}
if (b !== 0) {
magnitude = Math.max(magnitude, Math.floor(Math.log(Math.abs(b)) / Math.log(10)));
}
var epsilon = Math.pow(10, magnitude - 12);
if (Math.abs(r) < epsilon) {
r = 0;
}
return r;
};
H.feq10 = function (a, b) {
if (a === undefined || a === null || b === undefined || b === null ||
H.badnumber(a) || H.badnumber(b)) {
return false;
}
var epsilon = 0; // exact comparison
if (a === 0 || b === 0) {
// comparison with pure zero is special case
epsilon = 1e-100;
} else {
var magnitude = Math.floor(Math.max(Math.log(Math.abs(b)) / Math.log(10),
Math.log(Math.abs(a)) / Math.log(10))) + 1;
// OR just in case magnitude is NaN (probably never)
epsilon = Math.pow(10, magnitude - 10) || 1e-100;
}
return H.feq(a, b, epsilon);
};
H.feq_digits = function (a, b, precision_digits, epsilon, log)
{
if (a === undefined || a === null || b === undefined || b === null ||
H.badnumber(a) || H.badnumber(b)) {
return false;
}
if (! epsilon) {
epsilon = 5;
}
precision_digits = Math.min(precision_digits, 10);
var magnitude;
// effectively moving the magnitude to zero
while (a === 0 || b === 0) {
a += 1;
b += 1;
}
var magnitude_b = Math.log(Math.abs(b)) / Math.log(10);
var magnitude_a = Math.log(Math.abs(a)) / Math.log(10);
magnitude = Math.max(magnitude_a, magnitude_b);
// Just in case magnitude is NaN
magnitude = (Math.floor(magnitude) + 1) || 0;
epsilon *= Math.pow(10, magnitude - precision_digits - 1);
if (log) {
window.xlog(" feq_digits " + a + " " + b + " " + (a - b) + " mag=" +
magnitude + " d=" + precision_digits +
" e=" + epsilon + " res " +
H.feq(a, b, epsilon));
}
return H.feq(a, b, epsilon);
};
// comparision with 10^-10 tolerance when one of the values tend to zero
H.feq10_0 = function (a, b)
{
var offset = 0;
if ((a <= 1 && a >= -1) || (b <= 1 && b >= -1)) {
offset = 2;
}
return H.feq10(offset + a, offset + b);
};
H.polar = function (x, y) {
var angle = Math.atan2(y, x); // does not throw NaN
var r = Math.sqrt(x * x + y * y);
return [r, angle];
};
H.orthogonal = function (r, angle)
{
return [r * H.cos(angle), r * H.sin(angle)];
};
H.fatorial = function (n)
{
var res = 1;
while (n > 1 && ! H.badnumber(res)) {
res *= n;
--n;
}
return res;
};
// from Wikipedia
H.gamma = function (z) {
if (z < 0.5) {
return Math.PI / (Math.sin(Math.PI * z) * H.gamma(1 - z));
}
z = z - 1;
var x = H.gamma.p[0];
for (var i = 1; i < (H.gamma.g + 2); ++i) {
x += H.gamma.p[i] / (z + i);
}
var t = z + H.gamma.g + 0.5;
return Math.sqrt(2 * Math.PI) * Math.pow(t, (z + 0.5)) * Math.exp(-t) * x;
};
H.gamma.g = 7;
H.gamma.p = [0.99999999999980993, 676.5203681218851,
-1259.1392167224028, 771.32342877765313, -176.61502916214059,
12.507343278686905, -0.13857109526572012, 9.9843695780195716e-6,
1.5056327351493116e-7];
H.fatorial_gamma = function (n)
{
if (n >= 0 && Math.floor(n) == n) {
return H.fatorial(n);
}
return H.gamma(n + 1);
};
H.permutations = function (a, b)
{
return H.fatorial(a) / H.fatorial(a - b);
};
H.combinations = function (a, b)
{
return H.permutations(a, b) / H.fatorial(b);
};
H.stddev = function (mem)
{
if (Math.abs(mem[H.STAT_N]) <= 1 ||
(mem[H.STAT_N] * mem[H.STAT_X2] - mem[H.STAT_X] * mem[H.STAT_X]) < 0 ||
(mem[H.STAT_N] * mem[H.STAT_Y2] - mem[H.STAT_Y] * mem[H.STAT_Y]) < 0) {
return [0];
}
var x = Math.pow((mem[H.STAT_N] * mem[H.STAT_X2] - mem[H.STAT_X] * mem[H.STAT_X]) /
(mem[H.STAT_N] * (mem[H.STAT_N] - 1)), 0.5);
var y = Math.pow((mem[H.STAT_N] * mem[H.STAT_Y2] - mem[H.STAT_Y] * mem[H.STAT_Y]) /
(mem[H.STAT_N] * (mem[H.STAT_N] - 1)), 0.5);
return [1, x, y];
};
H.linear_regression = function (mem)
{
if (Math.abs(mem[H.STAT_N]) <= 1) {
// window.xlog("LR err type 1");
return [0];
}
var div = mem[H.STAT_X2] - mem[H.STAT_X] * mem[H.STAT_X] / mem[H.STAT_N];
if (H.feq10_0(div, 0)) {
// window.xlog("LR err type 2");
return [0];
}
// TODO implement test [ n Ex2 - (Ex)2] [ n Ey2 - (Ey)2] <= 0
var avgx = mem[H.STAT_X] / mem[H.STAT_N];
var avgy = mem[H.STAT_Y] / mem[H.STAT_N];
var B = mem[H.STAT_XY] - mem[H.STAT_X] * mem[H.STAT_Y] / mem[H.STAT_N];
B /= div;
B = H.solve_infinity(B) || 0;
var A = avgy - B * avgx;
// note: vars are following the HP12C handbook convention
// y=Bx+A, while the 11C and math convention is y=Ax+B.
return [1, A, B];
};
H.stat_kr = function (mem, is_x, xx)
{
var res = H.linear_regression(mem);
if (! res[0]) {
// window.xlog("statkr error 1");
return [0];
}
var A = res[1];
var B = res[2];
// note: vars are following the HP12C handbook convention
// y=Bx+A, while the 11C and math convention is y=Ax+B.
// an equivalent test is already made at linear_regression()
/*
if (H.feq((mem[H.STAT_N] * mem[H.STAT_X2] - mem[H.STAT_X] * mem[H.STAT_X]), 0)) {
window.xlog("statkr error 2");
return [0];
}
*/
var rr3 = mem[H.STAT_Y2] - mem[H.STAT_Y] * mem[H.STAT_Y] / mem[H.STAT_N];
if (H.feq10_0(rr3, 0)) {
// window.xlog("statkr error 3");
return [0];
}
var rr1 = mem[H.STAT_XY] - mem[H.STAT_X] * mem[H.STAT_Y] / mem[H.STAT_N];
var rr2 = mem[H.STAT_X2] - mem[H.STAT_X] * mem[H.STAT_X] / mem[H.STAT_N];
/*
// already checked in "statkr error 2" and "statkr error 3"
if (rr2 === 0 || rr3 === 0) {
window.xlog("statkr error 5");
return [0];
}
*/
if ((rr2 * rr3) < 0) {
// window.xlog("statkr error 6");
return [0];
}
var rr = Math.sqrt(rr2 * rr3);
// invert signal in case of negative N
rr *= H.binary_sgn(mem[H.STAT_N]);
var r = rr1 / rr;
var c;
if (is_x) {
if (H.feq10_0(B, 0)) {
// window.xlog("statkr error 7");
return [0];
}
c = (xx - A) / B;
} else {
c = A + B * xx;
}
c = H.solve_infinity(c) || 0;
r = H.solve_infinity(r) || 0;
return [1, c, r];
};
H.stat_accumulate = function (sgn, mem, x, y)
{
mem[H.STAT_N] += sgn;
mem[H.STAT_X] += sgn * x;
mem[H.STAT_X2] += sgn * x * x;
mem[H.STAT_Y] += sgn * y;
mem[H.STAT_Y2] += sgn * y * y;
mem[H.STAT_XY] += sgn * x * y;
};
H.stat_avg = function (mem)
{
if (mem[H.STAT_N] === 0) {
return [0];
}
var x = mem[H.STAT_X] / mem[H.STAT_N];
var y = mem[H.STAT_Y] / mem[H.STAT_N];
return [1, x, y];
};
H.stat_avgw = function (mem)
{
if (mem[H.STAT_X] === 0) {
return [0];
}
return [1, mem[H.STAT_XY] / mem[H.STAT_X]];
};
H.bg_plus = function (a, b)
{
while (a.length < b.length) {
a = "0" + a;
}
while (b.length < a.length) {
b = "0" + b;
}
var carry = 0;
var res = "";
for (var i = 0; i < a.length; ++i) {
var aa = parseInt(a.substr(a.length - 1 - i, 1), 10);
var bb = parseInt(b.substr(b.length - 1 - i, 1), 10);
var p = aa + bb + carry;
res = (p % 10).toFixed(0) + res;
carry = Math.floor(p / 10);
}
res = carry.toFixed(0) + res;
var significant = 0;
while (res.charAt(significant) === "0" && significant < (res.length - 1)) {
++significant;
}
return res.substr(significant);
};
H.bg_mul1 = function (a, b)
{
var tot = "0";
for (var i = 0; i < a.length; ++i) {
var multiplier = a.charAt(a.length - 1 - i);
var partial = (parseInt(multiplier, 10) * parseInt(b, 10)).toFixed(0);
for (var j = 0; j < i; ++j) {
partial += "0";
}
tot = H.bg_plus(tot, partial);
}
return tot;
};
H.bg_mul = function (a, b)
{
var tot = "0";
for (var i = 0; i < b.length; ++i) {
var multiplier = b.charAt(b.length - 1 - i);
var partial = H.bg_mul1(a, multiplier);
for (var j = 0; j < i; ++j) {
partial += "0";
}
tot = H.bg_plus(tot, partial);
}
return tot;
};
H.prng_next = function (seed) {
var n = H.bg_plus(H.bg_mul("1574352261", seed.toFixed(0)), "1017980433");
return parseInt(n.substr(n.length - 10), 10);
};
H.prng_seed = function (seed) {
seed = Math.abs(seed);
if (seed <= H.value_min) {
return 0;
}
var exponent = Math.max(-1, Math.floor(Math.log(seed) / Math.log(10)));
seed = Math.floor(seed * Math.pow(10, 10 - 1 - exponent));
seed = Math.min(9999999999, Math.max(0, seed));
return seed;
};
H.Prng = function (seed)
{
var self = {};
self.seed = H.prng_seed(seed || 0);
self.random = function ()
{
self.seed = H.prng_next(self.seed);
return self.seed / 10000000000;
};
return self;
};
H.sin = function (r)
{
r = r % (2 * Math.PI);
var res = Math.sin(r);
if (Math.abs(res) <= 2.5e-16) {
res = 0;
}
return res;
};
H.cos = function (r)
{
r = r % (2 * Math.PI);
var res = Math.cos(r);
if (Math.abs(res) <= 2.5e-16) {
res = 0;
}
return res;
};
H.tan = function (r)
{
r = r % Math.PI;
var res = H.sin(r) / H.cos(r);
if (res > H.value_max) {
res = H.value_max;
} else if (res < -H.value_max) {
res = -H.value_max;
}
return res;
};
H.complex_ln = function (arg)
{
var polar = H.complex_to_polar(arg);
var a_len = polar.r;
var a_angle = polar.i;
if (a_len === 0) {
// avoids a failure mode, and 0^z=0
return {r: 0, i: 0, h: 0, err: true};
}
return {r: Math.log(a_len), i: a_angle, h: 0, err: false};
};
H.complex_to_polar = function (arg)
{
var len = H.complex_abs(arg).r;
var angle = Math.atan2(arg.i, arg.r); // always returns a valid number
return {r: len, i: angle, h: 0};
};
H.complex_abs = function (y)
{
var real = Math.sqrt(y.r * y.r + y.i * y.i);
return {r: real, i: 0, h: 0};
};
H.sve = 40.0;
H.kve = "a01ad46171d3fb24da06fdd79c7dabda";
H.kve2 = "a30f0de855f9665f65ef450e486956c6acfc4772";
/*jslint white: true, undef: true, nomen: true, regexp: true, strict: true, browser: true, bitwise: true */
/*jshint globalstrict: true*/
/*global H */
"use strict";
function Hp12c_pgrm()
{
var self = this;
self.constructor();
}
Hp12c_pgrm.prototype.constructor = function ()
{
var self = this;
self.exec_special = [];
self.exec_special[H.GTO] = [2, 1, self.p_exec_gto];
self.exec_special[H.GSB] = [2, 1, self.p_exec_gosub];
if (H.type === "15c") {
// 15C: see remark [1]
self.exec_special[H.GTO_DOT] = [3, 1, self.p_exec_gto_dot];
self.exec_special[H.GSB_DOT] = [3, 1, self.p_exec_gosub_dot];
}
self.exec_special[H.GG * 100 + H.GSB] = [2, 0, self.p_exec_rtn];
self.exec_special[H.dispatcher.KEY_RS] = [1, 0, self.p_exec_rs];
self.label_count = 0;
self.type_special = [];
var t = self.type_special;
t[H.GG * 100 + H.dispatcher.KEY_RS] = self.p_type_pr;
t[H.dispatcher.KEY_SST] = self.p_type_sst;
t[H.GG * 100 + H.dispatcher.KEY_SST] = self.p_type_bst;
t[H.dispatcher.KEY_BACKSPACE] = self.p_type_del;
t[H.FF * 100 + H.dispatcher.KEY_RDOWN] = self.p_type_clear_pgrm;
if (H.type === "15c") {
t[H.GTO * 100 + H.dispatcher.KEY_CHS] = self.p_type_gto_move_begin;
} else {
t[H.GTO * 100 + H.dispatcher.KEY_DECIMAL] = self.p_type_gto_move_begin;
}
t[H.GTO] = self.p_type_gto_begin;
t[H.GSB] = self.p_type_gosub_begin;
t[H.LBL] = self.p_type_label_begin;
if (H.type === "15c") {
t[H.GTO_DOT] = self.p_type_gto_dot_begin;
t[H.GSB_DOT] = self.p_type_gosub_dot_begin;
t[H.LBL_DOT] = self.p_type_label_dot_begin;
}
if (H.type === "11c" || H.type === "15c") {
t[H.GG * 100 + H.RCL] = self.p_type_mem_info;
t[H.FF * 100 + H.RCL] = self.p_type_user;
if (H.type === "15c") {
self.label_count = 25;
} else {
self.label_count = 15;
}
} else if (H.type === "16c") {
t[H.FF * 100 + 0] = self.p_type_mem_info;
self.label_count = 16;
}
for (var n = 0; n <= 9; ++n) {
t[H.GTO_MOVE * 100 + n] = self.p_type_gto_move_n;
t[H.GTO * 100 + n] = self.p_type_gto_n;
t[H.GSB * 100 + n] = self.p_type_gosub_n;
t[H.LBL * 100 + n] = self.p_type_label_n;
if (H.type === "15c") {
t[H.GTO_DOT * 100 + n] = self.p_type_gto_dot_n;
t[H.GSB_DOT * 100 + n] = self.p_type_gosub_dot_n;
t[H.LBL_DOT * 100 + n] = self.p_type_label_dot_n;
}
}
var lc = self.label_count;
if (H.type === "15c") {
// label count goes up to 25 but we really want
// here is the range of letters here (A..E).
lc = 15;
}
for (n = 11; n <= lc; ++n) {
t[H.GTO * 100 + n] = self.p_type_gto_n;
t[H.GSB * 100 + n] = self.p_type_gosub_n;
t[H.LBL * 100 + n] = self.p_type_label_n;
}
// 15c: no dot handling for index
t[H.GTO * 100 + H.KEY_INDEX] = self.p_type_gto_n;
t[H.GSB * 100 + H.KEY_INDEX] = self.p_type_gosub_n;
self.execution_delay = 80;
self.default_execution_delay = self.execution_delay;
self.fast_stack = 0;
self.stack_size = 4;
if (H.type === "15c") {
self.stack_size = 8;
}
self.sched_timer = null;
};
Hp12c_pgrm.p_encode_key = function (key, addr)
{
var self = this;
var opcode;
if (addr) {
opcode = H.zeropad(key.toFixed(0), H.ram_ADDR_SIZE);
} else {
opcode = H.zeropad(key.toFixed(0), H.INSTRUCTION_SIZE);
}
return opcode;
};
Hp12c_pgrm.p_expand_opcode = function (modifier)
{
var self = this;
var a = [];
// Expands an opcode or modifier codified like 100 * op0 + op1
if (modifier >= H.INSTRUCTION_MAX) {
// composite modifier; recurse
a = Hp12c_pgrm.p_expand_opcode(Math.floor(modifier / 100));
}
a.push(modifier % H.INSTRUCTION_MAX);
return a;
};
Hp12c_pgrm.p_encode_modifier = function (modifier)
{
var self = this;
if (modifier <= 0) {
return "";
}
var opcode = "";
var expanded = Hp12c_pgrm.p_expand_opcode(modifier);
for (var i = 0; i < expanded.length; ++i) {
opcode += Hp12c_pgrm.p_encode_key(expanded[i], 0) + ".";
}
return opcode;
};
Hp12c_pgrm.p_encode_instruction = function (modifier, key, addr)
{
var self = this;
return Hp12c_pgrm.p_encode_modifier(modifier) +
Hp12c_pgrm.p_encode_key(key, addr);
};
Hp12c_pgrm.prototype.hex_opcode = function (instr)
{
var self = this;
var op = instr.split(".");
for (var i = 0; i < op.length; ++i) {
var key = parseInt(op[i], 10);
if (key >= 11 && key <= 16) {
op[i] = (key - 1).toString(16);
}
}
return op.join(".");
};
Hp12c_pgrm.prototype.shrunk_opcode = function (instr)
{
var self = this;
var op = instr.split(".");
var modifier = 0;
var key = 0;
key = parseInt(op[op.length - 1], 10);
for (var i = 0; i < op.length - 1; ++i) {
modifier = 100 * modifier + parseInt(op[i], 10);
}
var K = H.dispatcher.functions;
if (K[key]) {
var closure = K[key][modifier];
if (closure) {
if (closure.shrink === 1) {
// convert 48 to "o"
var skey = parseInt(op[op.length - 2], 10);
if (skey === 48) {
var iop = op.slice(0, op.length - 2);
return iop.join(".") + ".o" + parseInt(op[op.length - 1], 10);
}
} else if (closure.shrink === 2) {
// convert 11..15 to letter
if (key >= 11 && key <= 16) {
op[op.length - 1] = (key - 1).toString(16);
}
}
}
}
return op.join(".");
};
Hp12c_pgrm.prototype.p_del = function (modifier, key, addr)
{
var self = this;
var ip = H.machine.ip;
var limit = H.machine.program_limit();
if (ip <= 0 || ip > limit) {
H.machine.ip = 0;
return;
}
for (var e = ip; e < limit; ++e) {
H.machine.ram[e] = H.machine.ram[e + 1];
}
H.machine.ram[limit] = H.STOP_INSTRUCTION;
--H.machine.ip;
--H.machine.program_size;
};
Hp12c_pgrm.prototype.log = function (msg)
{
var self = this;
if (! H.machine.rapid) {
window.xlog(msg);
}
};
Hp12c_pgrm.prototype.p_poke = function (modifier, key, addr)
{
var self = this;
if ((H.machine.ip + 1) >= H.ram_MAX) {
self.log("pgrm: IP limit bumped");
H.machine.display_error(H.ERROR_IP);
return false;
}
if (H.machine.program_size >= H.ram_MAX) {
self.log("pgrm: program size limit bumped");
H.machine.display_error(H.ERROR_IP);
return false;
}
++H.machine.ip;
++H.machine.program_size;
// anyone except 12C inserts instructions
for (var e = H.ram_MAX - 1; e > H.machine.ip; --e) {
H.machine.ram[e] = H.machine.ram[e - 1];
}
H.machine.ram[H.machine.ip] =
Hp12c_pgrm.p_encode_instruction(modifier, key, addr);
return true;
};
Hp12c_pgrm.prototype.p_sched = function ()
{
var self = this;
if (self.sched_timer) {
H.cancel_delay(self.sched_timer);
self.sched_timer = null;
}
if (H.machine.program_mode >= H.RUNNING) {
H.machine.display_pgrm();
if (H.machine.modal() > 0) {
// call us back when exits from modal
window.console.ut_snap("halt ");
H.machine.modal_observer("p_sched", function () {
window.console.ut_snap("resum");
self.p_sched();
});
return;
}
H.machine.modal_observer_remove("p_sched");
self.sched_timer = H.delay(function () {
self.sched_timer = null;
self.p_execute();
}, (H.machine.rapid ? 0 : self.execution_delay));
}
};
Hp12c_pgrm.prototype.p_gto = function (label)
{
var self = this;
var is_label = true;
var new_ip = label;
var low = 11; // key for letter 'A'
var high = self.label_count; // key for letter 'E' or 'F'
if (H.type === "15c") {
// 15C uses label 10-19 for LBL . 0-9
low = 10;
// letter A-F goes to 20-24
high = 24;
}
if (label == H.KEY_INDEX) {
// index-based gto
if (H.machine.index >= 0) {
// label in index
new_ip = Math.floor(H.machine.index);
if (new_ip >= self.label_count) {
self.log("Invalid label in index: " + new_ip);
return false;
}
if (new_ip >= 10 && H.type !== "15c") {
// move from 10..14 to 11..15 range (letter keystrokes)
// (15c uses range 20-24 for letters: no move!)
new_ip += 1;
}
} else {
// absolute address in index
new_ip = Math.floor(Math.abs(H.machine.index));
is_label = false;
if (new_ip > H.machine.program_limit()) {
self.log("Invalid IP in index: " + new_ip);
return false;
}
}
} else {
// hard-coded label
// in 11C and 16c, it is the key code for A-F (11.16)
}
if (is_label) {
self.log("GTO to label " + new_ip);
new_ip = self.find_label(new_ip);
if (! new_ip) {
self.log("... no such label");
return false;
}
}
self.log("GTO to ip " + new_ip);
H.machine.ip = new_ip;
if (H.type === "16c") {
H.machine.display_result_s(false, true);
} else {
H.machine.display_result_s(false, false);
}
return true;
};
Hp12c_pgrm.prototype.p_do_gto = function (addr)
{
var self = this;
// handled in special way because it changes IP
H.machine.rst_modifier(1);
if (! self.p_gto(addr)) {
H.machine.display_error(H.ERROR_IP);
self.stop(2);
return;
}
};
Hp12c_pgrm.prototype.p_exec_gto = function (op)
{
var self = this;
// if 15c, keys 11..15 translated to label range 20..24
return self.p_do_gto(self.fix_label_key(op[1]));
};
Hp12c_pgrm.prototype.p_exec_gto_dot = function (op)
{
var self = this;
return self.p_do_gto(op[2] + 10);
};
Hp12c_pgrm.prototype.p_do_gosub = function (addr)
{
var self = this;
if (H.machine.call_stack.length >= self.stack_size) {
H.machine.display_error(H.ERROR_RTN);
self.stop(2);
return;
}
var new_ip = self.find_label_or_index(addr);
if (! new_ip) {
H.machine.display_error(H.ERROR_IP);
self.stop(2);
return;
}
self.log("GSB label " + addr + " to " + new_ip);
self.push_stack(new_ip);
if (H.type === "16c") {
H.machine.display_result_s(false, true);
} else {
H.machine.display_result_s(false, false);
}
};
Hp12c_pgrm.prototype.p_exec_gosub = function (op)
{
var self = this;
// if 15c, keys 11..15 translated to label range 20..24
return self.p_do_gosub(self.fix_label_key(op[1]));
};
Hp12c_pgrm.prototype.p_exec_gosub_dot = function (op)
{
var self = this;
return self.p_do_gosub(op[2] + 10);
};
Hp12c_pgrm.prototype.p_exec_rtn = function (op)
{
var self = this;
self.pop_stack();
self.log("RTN to " + H.machine.ip);
// do nothing since p_execute() will stop if ip=0
if (H.type === "16c") {
H.machine.display_result_s(false, true);
} else {
H.machine.display_result_s(false, false);
}
};
Hp12c_pgrm.prototype.p_exec_rs = function (op)
{
var self = this;
++H.machine.ip;
self.stop(0);
H.machine.rst_modifier(1);
};
Hp12c_pgrm.p_opcode_match = function (candidate, model, comparison_len)
{
var self = this;
model = Hp12c_pgrm.p_expand_opcode(model);
for (var i = 0; i < comparison_len; ++i) {
if (candidate[i] != model[i]) {
return false;
}
}
return true;
};
Hp12c_pgrm.prototype.p_exec_handle_special = function (op)
{
var self = this;
var handler = null;
for (var prefix in self.exec_special) {
if (typeof prefix !== "object") {
var expected_len = self.exec_special[prefix][0];
var suffix_len = self.exec_special[prefix][1];
var f = self.exec_special[prefix][2];
if (expected_len != op.length) {
continue;
}
if (! Hp12c_pgrm.p_opcode_match(op, prefix,
expected_len - suffix_len)) {
continue;
}
handler = f;
break;
}
}
if (handler) {
handler.call(self, op);
}
return !!handler;
};
Hp12c_pgrm.prototype.find_label = function (lab)
{
var self = this;
var template_modifier = H.LBL;
var template_label = lab;
if (H.type === "15c") {
if (template_label >= 10 && template_label <= 19) {
template_modifier = H.LBL_DOT;
template_label -= 10;
} else if (template_label >= 20 && template_label <= 24) {
template_label -= 20;
template_label += 11;
}
}
var template = Hp12c_pgrm.p_encode_instruction(template_modifier, template_label, 0);
var i;
// two-phase search to handle repeated labels correctly
for (i = H.machine.ip + 1; i <= H.machine.program_limit(); ++i) {
if (H.machine.ram[i] == template) {
return i;
}
}
for (i = 1; i <= H.machine.ip; ++i) {
if (H.machine.ram[i] == template) {
return i;
}
}
self.log("find_label: not found " + lab);
return 0;
};
Hp12c_pgrm.prototype.find_label_or_index = function (label_or_index)
{
var self = this;
if (label_or_index === H.KEY_INDEX) {
if (H.machine.index >= 0) {
// label in index
var label = Math.floor(H.machine.index);
if (label >= self.label_count) {
self.log("find_label_or_index: Invalid label in index: " + label);
return 0;
}
if (label >= 10 && H.type !== "15c") {
// put in 11..count range (= letter keys)
// 15C: no gap, no change!
label += 1;
}
return self.find_label(label);
} else {
// absolute address in index
var new_ip = Math.floor(Math.abs(H.machine.index));
if (new_ip > H.machine.program_limit()) {
return 0;
}
return new_ip;
}
}
return self.find_label(label_or_index);
};
Hp12c_pgrm.prototype.clean_stack = function ()
{
var self = this;
H.machine.call_stack = [];
};
Hp12c_pgrm.prototype.push_stack = function (ip)
{
var self = this;
H.machine.call_stack.push(H.machine.ip + 1);
H.machine.ip = ip;
};
Hp12c_pgrm.prototype.pop_stack = function ()
{
var self = this;
if (H.machine.call_stack.length <= 0) {
H.machine.ip = 0;
return false;
}
var ip = H.machine.call_stack[H.machine.call_stack.length - 1];
H.machine.call_stack.splice(H.machine.call_stack.length - 1, 1);
if (ip > H.machine.program_limit()) {
self.log("RTN to EOF, defaulting to 0");
ip = 0;
}
H.machine.ip = ip;
return true;
};
// can only be called as a deferred call from p_sched()
Hp12c_pgrm.prototype.p_execute = function ()
{
var self = this;
if (H.machine.program_mode < H.RUNNING) {
// may happen if a key is pressed between p_sched()
// and the deferred call to this method
return;
}
window.console.ut_snap("pre ");
if (H.machine.ip > H.machine.program_limit()) {
// top of RAM
// in 12c, pop_stack() always fails because GSB is never called
self.pop_stack();
if (H.machine.ip <= 0) {
self.clean_stack();
self.stop(0);
return;
} else {
self.log("implicit RTN to " + H.machine.ip);
}
}
// should never happen; tested by error injection in stack
if (H.machine.ip <= 0) {
H.machine.ip = 1;
H.machine.display_pgrm();
}
var op_txt = H.machine.ram[H.machine.ip];
// should never happen; tested by error injection in stack
if (! H.is_12c() && H.type !== "10c") {
if (op_txt == H.STOP_INSTRUCTION || op_txt === "") {
// bumped soft end of program (GTO 00)
H.machine.ip = 0;
self.stop(0);
return;
}
}
var op = op_txt.split(".");
var log;
if (! H.machine.rapid) {
log = op_txt; /* + " " + H.machine.x;
if (H.type === "15c") {
log += ":" + H.machine.xi;
if (H.machine.xh) {
log += ":M";
}
}
*/
}
var e;
for (e = 0; e < op.length; ++e) {
op[e] = parseInt(op[e], 10);
}
if (! self.p_exec_handle_special(op)) {
// not special; execute via dispatcher
for (e = 0; e < op.length; ++e) {
if (!H.dispatcher.dispatch_common(op[e], true)) {
self.log("Invalid opcode for exec: " + op_txt);
}
}
window.console.ut_snap("pos ");
if (H.machine.program_mode >= H.RUNNING || ! H.machine.is_error()) {
// sticks at error opcode
++H.machine.ip;
}
} else {
window.console.ut_snap("posp ");
}
if (! H.machine.rapid) {
/*
log += " -> " + H.machine.x;
if (H.type === "15c") {
log += ":" + H.machine.xi;
if (H.machine.xh) {
log += ":M";
}
}
*/
self.log(log);
}
// instruction execution aftermath
if (H.machine.ip <= 0) {
// GTO 00, RTN to empty, or equivalent
self.stop(0);
} else if (H.machine.program_mode === H.RUNNING_STEP) {
H.machine.program_mode = H.INTERACTIVE;
H.machine.display_pgrm();
} else if (H.machine.program_mode === H.RUNNING) {
self.p_sched();
}
// Warning: 15c's SOLVE and INTG put machine in interactive
// mode so they can run the programmed function
};
Hp12c_pgrm.prototype.p_run = function ()
{
var self = this;
H.machine.program_mode = H.RUNNING;
if (H.machine.ip <= 0) {
self.clean_stack();
H.machine.ip = 1;
}
H.machine.display_pgrm();
H.display.recycle();
self.p_sched();
};
Hp12c_pgrm.prototype.run = function ()
{
var self = this;
self.p_run();
};
Hp12c_pgrm.prototype.rs = function ()
{
var self = this;
// when executing program, p_exec_rs is called instead
if (H.machine.program_mode == H.INTERACTIVE) {
H.machine.display_result_s(false, false);
self.p_run();
}
H.machine.rst_modifier(1);
};
Hp12c_pgrm.prototype.p_type_pr = function (key)
{
var self = this;
// P/R in prog. mode exits programming mode
H.machine.rst_modifier(1);
H.machine.program_mode = H.INTERACTIVE;
if (H.is_12c() || H.type === "10c") {
H.machine.ip = 0;
}
H.machine.display_pgrm();
H.machine.display_modifier();
H.machine.display_result_s(false, false);
};
Hp12c_pgrm.prototype.p_type_sst = function (key)
{
var self = this;
if (++H.machine.ip > H.machine.program_limit()) {
H.machine.ip = 0;
}
H.machine.rst_modifier(1);
H.machine.display_program_opcode();
};
Hp12c_pgrm.prototype.p_type_bst = function (key)
{
var self = this;
if (--H.machine.ip < 0) {
H.machine.ip = H.machine.program_limit();
}
H.machine.rst_modifier(1);
H.machine.display_program_opcode();
};
Hp12c_pgrm.prototype.p_type_del = function (modifier, key, addr)
{
var self = this;
self.p_del();
H.machine.rst_modifier(1);
H.machine.display_program_opcode();
};
Hp12c_pgrm.prototype.p_type_clear_pgrm = function (key)
{
var self = this;
H.machine.clear_prog(1);
H.machine.rst_modifier(1);
H.machine.display_program_opcode();
};
Hp12c_pgrm.prototype.p_type_mem_info = function (key)
{
var self = this;
H.machine.rst_modifier(1);
H.machine.mem_info();
};
Hp12c_pgrm.prototype.p_type_user = function (key)
{
var self = this;
H.machine.rst_modifier(1);
H.machine.toggle_user();
};
Hp12c_pgrm.prototype.p_type_gto_move_n = function (key)
{
var self = this;
H.machine.gtoxx = "" + H.machine.gtoxx + key.toFixed(0);
if (H.machine.gtoxx.length >= H.ram_ADDR_SIZE) {
var ip = parseInt(H.machine.gtoxx, 10);
H.machine.gtoxx = "";
H.machine.rst_modifier(1);
if (ip > H.machine.program_limit()) {
H.machine.display_error(H.ERROR_IP);
return;
}
H.machine.ip = ip;
}
H.machine.display_program_opcode();
};
Hp12c_pgrm.prototype.fix_label_key = function (key)
{
var self = this;
if (H.type === "15c") {
// move keys 11..15 to label range 20..24
if (key >= 11 && key <= 15) {
key = key - 11 + 20;
}
}
return key;
};
Hp12c_pgrm.prototype.p_type_gto_n = function (key)
{
var self = this;
H.machine.rst_modifier(1);
return self.p_poke(H.GTO, key, 0) && H.machine.display_program_opcode();
};
Hp12c_pgrm.prototype.p_type_gto_dot_n = function (key)
{
var self = this;
H.machine.rst_modifier(1);
return self.p_poke(H.GTO_DOT, key, 0) && H.machine.display_program_opcode();
};
Hp12c_pgrm.prototype.p_type_gosub_n = function (key)
{
var self = this;
H.machine.rst_modifier(1);
return self.p_poke(H.GSB, key, 0) && H.machine.display_program_opcode();
};
Hp12c_pgrm.prototype.p_type_gosub_dot_n = function (key)
{
var self = this;
H.machine.rst_modifier(1);
return self.p_poke(H.GSB_DOT, key, 0) && H.machine.display_program_opcode();
};
Hp12c_pgrm.prototype.p_type_gosub_begin = function (key)
{
var self = this;
H.machine.set_modifier(H.GSB, 1);
H.machine.display_program_opcode();
return true;
};
Hp12c_pgrm.prototype.p_type_gosub_dot_begin = function (key)
{
var self = this;
H.machine.set_modifier(H.GSB_DOT, 1);
H.machine.display_program_opcode();
return true;
};
Hp12c_pgrm.prototype.p_type_label_n = function (key)
{
var self = this;
H.machine.rst_modifier(1);
return self.p_poke(H.LBL, key, 0) && H.machine.display_program_opcode();
};
Hp12c_pgrm.prototype.p_type_label_dot_n = function (key)
{
var self = this;
H.machine.rst_modifier(1);
return self.p_poke(H.LBL_DOT, key, 0) && H.machine.display_program_opcode();
};
Hp12c_pgrm.prototype.p_type_label_begin = function (key)
{
var self = this;
H.machine.set_modifier(H.LBL, 1);
H.machine.display_program_opcode();
return true;
};
Hp12c_pgrm.prototype.p_type_label_dot_begin = function (key)
{
var self = this;
H.machine.set_modifier(H.LBL_DOT, 1);
H.machine.display_program_opcode();
return true;
};
Hp12c_pgrm.prototype.p_type_gto_move_begin = function (key)
{
var self = this;
H.machine.set_modifier(H.GTO_MOVE, 1);
H.machine.display_program_opcode();
};
Hp12c_pgrm.prototype.p_type_gto_begin = function (key)
{
var self = this;
H.machine.set_modifier(H.GTO, 1);
if (H.is_12c() || H.type === "10c") {
H.machine.gtoxx = "";
}
H.machine.display_program_opcode();
return true;
};
Hp12c_pgrm.prototype.p_type_gto_dot_begin = function (key)
{
var self = this;
H.machine.set_modifier(H.GTO_DOT, 1);
H.machine.display_program_opcode();
return true;
};
Hp12c_pgrm.prototype.p_type_handle_special = function (key)
{
var self = this;
var handler = null;
var op = H.machine.modifier * 100 + key;
if (self.type_special[op]) {
self.type_special[op].call(self, key);
return true;
}
return false;
};
Hp12c_pgrm.prototype.type = function (key)
{
var self = this;
if (self.p_type_handle_special(key)) {
return false;
}
// non-special key; resolve using dispatcher mechanism
if (H.dispatcher.handle_modifier(key, 1)) {
H.machine.display_program_opcode();
return false;
}
// non-special, non-modifier
// USER already handled by dispatcher, even for pgrm mode
var f = H.dispatcher.find_function(key, 1, 0);
if (! f) {
self.log("pgrm typing: no handler for " + key);
H.machine.rst_modifier(1);
H.machine.display_program_opcode();
return false;
}
var m = H.machine.modifier;
H.machine.rst_modifier(1);
return self.p_poke(m, key, 0) && H.machine.display_program_opcode();
};
Hp12c_pgrm.prototype.stop = function (motive)
{
var self = this;
H.machine.program_mode = H.INTERACTIVE;
if (H.machine.ip > H.machine.program_limit()) {
H.machine.ip = 0;
}
H.machine.display_pgrm();
if (! H.machine.is_error()) {
if (H.type === "16c") {
H.machine.display_result_s(false, true);
} else {
H.machine.display_result();
}
}
H.machine.program_stopped(motive);
};
//////////////////////////////////////////////////////////////////////////
// Interactive mode commands
//////////////////////////////////////////////////////////////////////////
Hp12c_pgrm.prototype.sst = function ()
{
var self = this;
if (H.machine.program_mode == H.INTERACTIVE) {
if (H.machine.ip <= 0) {
H.machine.ip = 1;
}
H.machine.program_mode = H.RUNNING_STEP_PRE;
H.machine.display_program_opcode();
self.log("pgrm: SST interactive begin");
}
H.machine.rst_modifier(1);
};
// Executed when in mode RUNNING_STEP_PRE and user presses a key
// (this exceptional case is handled by hp1xc_dispatch)
Hp12c_pgrm.prototype.run_step_finish = function ()
{
var self = this;
self.log("pgrm: SST interactive end+run");
H.machine.program_mode = H.RUNNING_STEP;
// unlikely
H.machine.ip = (H.machine.ip <= 0) ? 1 : H.machine.ip;
H.machine.display_pgrm();
H.machine.display_modifier();
self.p_sched();
};
Hp12c_pgrm.prototype.bst = function ()
{
var self = this;
if (H.machine.ip > 0) {
--H.machine.ip;
}
H.machine.rst_modifier(1);
H.machine.display_program_opcode();
H.machine.enter_modal(H.MODAL_PRESS);
};
Hp12c_pgrm.prototype.gto = function (label)
{
var self = this;
if (! self.p_gto(label)) {
H.machine.display_error(H.ERROR_IP);
return;
}
};
Hp12c_pgrm.prototype.label = function (label)
{
var self = this;
self.log("LBL #" + label);
if (H.type === "16c") {
H.machine.display_result_s(false, true);
} else {
H.machine.display_result_s(false, false);
}
};
Hp12c_pgrm.prototype.gosub = function (label)
{
var self = this;
var new_ip = self.find_label_or_index(label);
if (! new_ip) {
H.machine.display_error(H.ERROR_IP);
return false;
}
self.clean_stack();
// this made execution to continue from current IP
// which is certainly not desirable
// self.push_stack(new_ip);
H.machine.ip = new_ip;
if (H.type === "16c") {
H.machine.display_result_s(false, true);
} else {
H.machine.display_result_s(false, false);
}
self.p_run();
return true;
};
Hp12c_pgrm.prototype.user = function (label)
{
var self = this;
var new_ip = self.find_label(label);
if (! new_ip) {
H.machine.display_error(H.ERROR_IP);
return;
}
H.machine.display_result();
self.clean_stack();
H.machine.ip = new_ip;
self.log("USER: exec from ip " + H.machine.ip);
self.p_run();
};
Hp12c_pgrm.prototype.rtn = function (label)
{
var self = this;
// does not unwind stack in interactive mode
H.machine.ip = 0;
};
Hp12c_pgrm.prototype.dis_table = null;
Hp12c_pgrm.prototype.add_dis = function (dmap, asm, reducible, m, k)
{
var self = this;
var is_addr = false;
var mnemonic = asm.toUpperCase();
if (reducible) {
if (m >= 10000) {
// m+k that cannot be an opcode in RAM
// (but there is another closure with the
// same mnemonic that does the same task)
return;
}
}
var opcode = Hp12c_pgrm.p_encode_instruction(parseInt(m, 10),
parseInt(k, 10),
is_addr);
dmap[opcode] = mnemonic;
};
Hp12c_pgrm.prototype.generate_dis_table = function ()
{
var self = this;
var K = H.dispatcher.functions;
var dmap = {};
self.dis_table = dmap;
for (var key in K) {
if (K.hasOwnProperty(key)) {
for (var modifier in K[key]) {
if (K[key].hasOwnProperty(modifier)) {
var closure = K[key][modifier];
if (closure.asm) {
self.add_dis(dmap, closure.asm,
closure.reducible,
modifier, key);
}
}
}
}
}
};
Hp12c_pgrm.prototype.disassemble = function (opcode)
{
var self = this;
if (! self.dis_table) {
self.generate_dis_table();
}
if (H.is_12c()) {
if (opcode.substr(0, 6) === "43.33.") {
return "GTO " + opcode.substr(6);
}
} else if (H.type === "10c") {
if (opcode.substr(0, 3) === "22.") {
return "GTO " + opcode.substr(3);
}
}
if (!self.dis_table[opcode]) {
return "???";
}
return self.dis_table[opcode];
};
Hp12c_pgrm.prototype.fast = function ()
{
var self = this;
++self.fast_stack;
self.execution_delay = 0;
};
Hp12c_pgrm.prototype.slow = function ()
{
var self = this;
if (self.fast_stack > 0) {
--self.fast_stack;
}
if (self.fast_stack === 0) {
self.execution_delay = self.default_execution_delay;
}
};
/*jslint white: true, undef: true, nomen: true, regexp: true, strict: true, browser: true, bitwise: true */
/*jshint globalstrict: true*/
/*global H, Hp12c_pgrm */
"use strict";
Hp12c_pgrm.prototype.constructor = function ()
{
var self = this;
self.exec_special = [];
self.exec_special[H.GTO] = [3, 1, self.p_exec_gto];
self.exec_special[H.dispatcher.KEY_RS] = [1, 0, self.p_exec_rs];
self.type_special = [];
var t = self.type_special;
t[H.FF * 100 + H.dispatcher.KEY_RS] = self.p_type_pr;
t[H.dispatcher.KEY_SST] = self.p_type_sst;
t[H.GG * 100 + H.dispatcher.KEY_SST] = self.p_type_bst;
t[H.dispatcher.KEY_BACKSPACE] = self.p_type_bst;
t[H.FF * 100 + H.dispatcher.KEY_RDOWN] = self.p_type_clear_pgrm;
t[H.GTO * 100 + H.dispatcher.KEY_DECIMAL] = self.p_type_gto_move_begin;
t[H.GG * 100 + H.dispatcher.KEY_RDOWN] = self.p_type_gto_begin;
t[H.GG * 100 + 9] = self.p_type_mem_info;
for (var n = 0; n <= 9; ++n) {
t[H.GTO_MOVE * 100 + n] = self.p_type_gto_move_n;
t[H.GTO * 100 + n] = self.p_type_gto_n;
}
self.execution_delay = 100;
};
Hp12c_pgrm.prototype.p_poke = function (modifier, key, addr)
{
var self = this;
if ((H.machine.ip + 1) >= H.ram_MAX) {
H.machine.display_error(H.ERROR_IP);
H.machine.ip = 0;
return false;
}
++H.machine.ip;
// The HP-12C *replaces* instructions on edit, does not insert them!
//
// for (var e = H.ram_MAX - 1; e > H.machine.ip; --e) {
// ram[e] = ram[e-1];
// }
H.machine.ram[H.machine.ip] =
Hp12c_pgrm.p_encode_instruction(modifier, key, addr);
return true;
};
Hp12c_pgrm.prototype.p_exec_gto = function (op)
{
var self = this;
// handled in special way because it changes IP
H.machine.ip = op[2];
H.machine.rst_modifier(1);
H.machine.display_result_s(false, false);
};
Hp12c_pgrm.prototype.p_type_gto_n = function (key)
{
var self = this;
H.machine.gtoxx = "" + H.machine.gtoxx + key.toFixed(0);
if (H.machine.gtoxx.length >= H.ram_ADDR_SIZE) {
var ip = parseInt(H.machine.gtoxx, 10);
H.machine.gtoxx = "";
H.machine.rst_modifier(1);
if (ip >= H.ram_MAX) {
H.machine.display_error(H.ERROR_IP);
return;
}
self.p_poke(H.GTO, ip, 1);
}
H.machine.display_program_opcode();
};
Hp12c_pgrm.prototype.type = function (key)
{
var self = this;
if (self.p_type_handle_special(key)) {
return;
}
// non-special key; resolve using dispatcher mechanism
if (! H.dispatcher.handle_modifier(key, 1)) {
// note that find_function may reset the modifier
var f = H.dispatcher.find_function(key, 1);
if (! f) {
window.xlog("pgrm typing: no handler for " + key);
H.machine.display_program_opcode();
H.machine.rst_modifier(1);
return;
}
var ok = self.p_poke(H.machine.modifier, key, 0);
H.machine.rst_modifier(1);
if (! ok) {
// keep error on screen
return;
}
}
H.machine.display_program_opcode();
};
/*jslint white: true, undef: true, nomen: true, regexp: true, strict: true, browser: true, bitwise: true */
/*jshint globalstrict: true*/
/*global H */
"use strict";
function Hp12c_storage()
{
}
Hp12c_storage.prototype.instruction_table = "0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
Hp12c_storage.prototype.addr_prefix = "$";
Hp12c_storage.prototype.compress_opcode = function (op)
{
var self = this;
var c_op = "";
var opcodelist = op.split('.');
for (var e = 0; e < opcodelist.length; ++e) {
var opcode = opcodelist[e];
var lopcode = opcode.length;
var nopcode = parseInt(opcode, 10);
if (lopcode == H.INSTRUCTION_SIZE && nopcode >= 0 && nopcode <= 50) {
c_op += self.instruction_table.charAt(nopcode);
} else if (lopcode == H.ram_ADDR_SIZE) {
c_op += self.addr_prefix;
if (nopcode < 64) {
c_op += self.instruction_table.charAt(nopcode);
} else {
c_op += self.instruction_table.charAt(Math.floor(nopcode / 64));
c_op += self.instruction_table.charAt(nopcode % 64);
}
} else {
// invalid instruction
return self.compress_opcode(H.STOP_INSTRUCTION);
}
}
return c_op.toString();
};
Hp12c_storage.prototype.decompress_opcode = function (c_op)
{
var self = this;
var op = "";
var aop = [];
var cc;
var ncc;
var err = 0;
var addr_mode = 0;
var addr_value = 0;
for (var e = 0; e < c_op.length; ++e) {
cc = c_op.charAt(e);
if (cc == self.addr_prefix) {
if ((aop.length < 1) || (addr_mode > 0)) {
err = 1;
break;
}
addr_mode = 1;
continue;
}
ncc = self.instruction_table.indexOf(cc);
if (ncc < 0) {
err = 1;
break;
}
if (addr_mode) {
addr_value = (addr_value * 64) + ncc;
if (addr_value >= Math.pow(10, H.ram_ADDR_SIZE)) {
err = 1;
break;
}
if (addr_value >= H.ram_MAX) {
err = 1;
break;
}
if (addr_mode == 1) {
aop.push(H.zeropad(addr_value, H.ram_ADDR_SIZE));
} else {
aop[aop.length - 1] = H.zeropad(addr_value, H.ram_ADDR_SIZE);
}
addr_mode += 1;
} else {
if (ncc > 49) {
err = 1;
break;
}
aop.push(H.zeropad(ncc, H.INSTRUCTION_SIZE));
}
}
if (err) {
op = H.STOP_INSTRUCTION;
} else if (aop.length > H.INSTRUCTION_TOKENS || aop.length < 1) {
op = H.STOP_INSTRUCTION;
} else {
op = aop.join('.');
/*
// protection against "old" 12c memory being loaded on 11c
if (op == "43.33.000" && H.STOP_INSTRUCTION != op) {
op = H.STOP_INSTRUCTION;
}
if (op == "43.33.00" && H.STOP_INSTRUCTION != op) {
op = H.STOP_INSTRUCTION;
}
*/
}
return op;
};
Hp12c_storage.prototype.marshal_array = function (a, type)
{
var self = this;
var mtxt = "A" + type;
for (var ex = 0; ex < a.length; ++ex) {
var data = a[ex];
if (type == 'X') {
data = self.compress_opcode(data);
}
mtxt += "!" + data;
mtxt = mtxt.toString();
}
return mtxt;
};
Hp12c_storage.prototype.unmarshal_array = function (target, dst_name, mtxt)
{
var self = this;
var dst = target[dst_name]; // must be already filled with 0s or anything
var type = mtxt.charAt(1);
mtxt = mtxt.slice(3);
var a = mtxt.split('!');
if (dst_name === "mA" || dst_name === "mB" || dst_name === "mC" ||
dst_name === "mD" || dst_name === "mE") {
// target is matrix, and initially empty
while (dst.length < a.length) {
dst.push(0);
}
}
for (var ex = 0; ex < a.length && ex < dst.length; ++ex) {
if (type == 'N') {
dst[ex] = parseFloat(a[ex]);
if (H.badnumber(dst[ex])) {
dst[ex] = 0;
}
} else {
// programming opcode
if (ex > 0) {
dst[ex] = self.decompress_opcode(a[ex]);
}
}
}
return;
};
Hp12c_storage.prototype.save_memory2 = function (target)
{
var self = this;
var expires = new Date();
expires.setTime(expires.getTime() + 7 * 24 * 60 * 60 * 1000); // timezone irrelevant
var sm = target.nvname + "=";
var i, k;
for (i = 0; i < target.nvN.length; ++i) {
k = target.nvN[i];
sm += k + ":" + target[k] + " ";
}
for (i = 0; i < target.nvAN.length; ++i) {
k = target.nvAN[i];
sm += k + ":" + self.marshal_array(target[k], 'N') + " ";
}
for (i = 0; i < target.nvAX.length; ++i) {
k = target.nvAX[i];
sm += k + ":" + self.marshal_array(target[k], 'X') + " ";
}
sm += "; expires=" + expires.toGMTString() + "; path=/";
return sm;
};
Hp12c_storage.prototype.save = function ()
{
var self = this;
// WARNING this method is overridden by widgets!
document.cookie = self.save_memory2(H.machine);
};
Hp12c_storage.prototype.get_memory = function ()
{
var self = this;
return self.save_memory2(H.machine);
};
Hp12c_storage.prototype.recover_memory2 = function (target, sserial)
{
var self = this;
var ck = sserial.split(';'); // gets all cookie variables for this site
for (var f = 0; f < ck.length; ++f) {
var cv = ck[f].split('='); // split cookie variable name and value
if (cv.length != 2) {
continue;
}
cv[0] = H.trim(cv[0]);
cv[1] = H.trim(cv[1]);
if (cv[0] != H.type_cookie) {
continue;
}
var sm = cv[1].split(' '); // internal variable separation
for (var e = 0; e < sm.length; ++e) {
var smpair = sm[e].split(':'); // each internal variable is name=value
if (smpair.length == 2 && smpair[0].length > 0 &&
smpair[1].length > 0 &&
target[smpair[0]] !== undefined) {
if (smpair[1].length >= 2 && smpair[1].charAt(0) == 'A') {
self.unmarshal_array(target, smpair[0], smpair[1]);
} else {
target[smpair[0]] = parseFloat(smpair[1]);
if (H.badnumber(target[smpair[0]])) {
target[smpair[0]] = 0;
}
}
}
}
}
if (H.is_12c()) {
return;
}
// calculate program_size
H.machine.program_size = 1;
for (var ee = 1; ee < H.ram_MAX; ++ee) {
if (H.machine.ram[ee] != H.STOP_INSTRUCTION) {
H.machine.program_size += 1;
} else {
break;
}
}
};
Hp12c_storage.prototype.load = function ()
{
var self = this;
// gets all cookie variables for this site
// WARNING this method is overridden by widgets!
self.recover_memory2(H.machine, document.cookie);
};
Hp12c_storage.prototype.set_memory = function (txt)
{
var self = this;
self.recover_memory2(H.machine, txt);
};
/*jslint white: true, undef: true, nomen: true, regexp: true, strict: true, browser: true, bitwise: true */
/*jshint globalstrict: true*/
/*global H, Hp12c_display, Hp12c_keyboard, Hp12c_debug, Hp12c_machine, Hp12c_storage, Hp12c_dispatcher, Hp12c_pgrm */
"use strict";
function Close_hp12c()
{
if (! Close_hp12c.done) {
H.storage.save();
Close_hp12c.done = 1;
}
}
Close_hp12c.done = 0;
function Init_hp12c()
{
H.display = new Hp12c_display();
H.keyboard = new Hp12c_keyboard();
H.debug = new Hp12c_debug(function (t) {
return H.format_result_tuple(t);
});
H.machine = new Hp12c_machine();
H.dispatcher = new Hp12c_dispatcher();
H.pgrm = new Hp12c_pgrm();
H.storage = new Hp12c_storage();
H.machine.init();
H.storage.load();
H.machine.display_all();
H.machine.sti("init");
window.onunload = Close_hp12c;
window.beforenunload = Close_hp12c;
document.onunload = Close_hp12c;
document.beforeunload = Close_hp12c;
}